Getting 'Unconfused' on React with TypeScript
2024-01-31
A practical guide to React and TypeScript integration
Today I worked on a number of things related to React. Many of which were great refreshers which have gone stale in my brain. There were also some new gotchas related to React-18, specifically the experimental new render approach. As I'm trying to get a mental model around each aspect of React, specifically when used along with TypeScript, I've decided to write this post in order to help 'compile' the different concepts.
The React functionalities I worked on today are:
props: Props are used when passing data from a parent component to a child component. These props can be all sorts of things like objects, arrays or any primitive really. The props can be used to influence dynamic behavior within the child component. The example I used today was passing a 'color' prop from a parent to a child and then seeing the child component render the color that was passed to it. The biggest thing that stood out related to props and TypeScript was the definition of TypeScript interfaces which define what those props should or should not contain. This is usually defined through a 'ChildProps' interface which can be used to define the properties that a prop should contain and it can even define what functions are expected within the props being passed to the child. The props interface also helps the parent component by defining what props the child component can receive.
useState: This is what's referred to as a 'React hook' which powers the reactivity of React. A useState hook follows the following pattern, a restructured const is defined, which has two pieces, one is the variable that defines the current state and the other is the callback function which will be used to update the state. The state variable and function are then defined elsewhere in the component to define state and the actions which lead to an updated state. The updated state is based on the business logic that should be executed within the function in order to update the state accordingly. When using the useState functionality with TypeScript it's important to define what the state variable data type should be otherwise the compiler will start throwing all sorts of errors. it's also important to define what return data type the function which updates the state should return.
events: Events are not a new concept, but when working with events in React with TypeScript, the biggest takeaway is making sure the types are defined for the events. So for example if there is a draggable event, then the type for that event should be explicitly defined with the appropriate HTML element event data type. This is easy to find through VSCode (thank you tool-tips), but very important to include when defining your events in a React component that uses TypeScript.
useEffect: When you want to execute some kind of logic upon loading the page, the useEffect functionality is the right tool. I used this along with refs in order to bring focus on the page to a particular HTML element upon loading the page. The way refs work is you define the ref on the HTML element and then 'reference' that ref in the useEffect function which drives the focus to that element. Similarly to events, it's really important when working with TypeScript to ensure that the HTML element data types are called out when defining the refs. Especially with refs, it's important to explicitly call out if the ref could be null (through union types) and make sure you are putting type-guards in place to ensure the value is not null to avoid any unexpected behavior.
Class Components: The last thing I want to compile is class components and functional components. I feel like this is a much deeper conversation and I want to dive deeper into when to use one versus the other. Personally, I am attracted to the syntactic sugar of class components. The syntax clicks a little more than with functional components. Maybe it's because of my Java background, or maybe just because of the way my brain's wired. But the functionality of the components is identical, it's just a matter of different code structures and modules being used within the file. Definitely a topic I want to dive deeper into, but for now the main difference I've come to understand between class and functional components is pretty much the syntax.