React Hooks — What Are They and How to Create Your Own

Kelsey Greene
Geek Culture
Published in
5 min readApr 8, 2021

--

React Hooks are a new addition to the React API — introduced in React v16.8.0. On the face of it, Hooks depart from the classic class component structure of React significantly and can seem daunting. Coupled with the fact that classes are still here to stay and the API itself hasn’t been adjusted to necessitate the use of Hooks, some may be slow to adopt them. However, once you are familiar with them, Hooks are a conciser and more straightforward way to organize code and manage state, making them a wonderful addition to your React toolbelt!

A quick example of the useState hook in action

So, what is a Hook?

Hooks are functions that live inside React’s functional components, that enable you to more easily “grab” and work with state, as well as the various React lifecycle events. Note that these can only live in functional components and are meant to replace the need for classes (though they can be used alongside each other, and Hooks are made to be backward-compatible, meaning that you can slowly incorporate them into already existing code if you would like, without it causing breaking changes.) They cannot live in standard Javascript functions — except in the case of making your own custom hook, which I will touch upon later.

Apart from only being able to live in a functional component or a custom Hook, the other cardinal rule to remember for hooks is this: they must be called at the top level of a function — this means no nested functions, no loops, no early returns, no conditionals. Why? Take a look at the code snippet below:

Example of Hooks being called multiple times in a single component.

What is going on here? In this particular functional component, we are calling the Hooks useState and useEffect multiple times. So how does the code know which state is corresponding to which Hook? Hooks look to their order within the component to determine what state they correspond with, always. If this order were to change at each render, React wouldn’t know what to return at each call, leading to unintended side effects and bugs! If you do find yourself needing something to run conditionally, simply put the conditional inside your Hook. If this seems like something you are liable to forget, React has created a special ESlint plug-in that will enforce these two rules for you!

Common Hooks and How to Use Them

The most “popular” and probably most straight-forward Hook you will use is the useState Hook. The useState Hook adds local state to a component and preserves it across re-renders. It takes in an initial state as argument, and unlike this.state, it doesn’t need to be an object unless you want it to be. This argument will only be used on the first render. The hook returns two things: 1. a value holding the current local state, and 2. a function that allows you to update the local state. A best practice for structuring these useState Hooks, is to name the values that will be returned via array destructuring. An example of this is demonstrated below.

const [font, setFont] = useState(“arial”)

You can name these variables whatever you would like, but the first will be assigned to the local state that is returned, while the second will correspond to the function that allows you to update the local state. Your function to update state can then be called anywhere within the component based on your needs.

The useEffect Hook is also one that will seem familiar. This Hook can be thought of as componentDidMount, componentWillUnmount and componentDidUpdate all rolled into one simple hook. Any code that will cause side effects (like updating the DOM or fetching data) can be housed here. This Hook takes in your side-effect-causing function and will call it after every render of the component. Because it lives in the component, it can leverage JS closure to access state and any other potential props. This can be a great place to call your update state function! This Hook also does not block your browser from updating the screen (unlike componentDidMount & componentWillUpdate.) This can be really handy as it can help the user experience feel more fluid and responsive, but note that if you do need effects to occur synchronously, this may not be the Hook for you! Go check out the useLayoutEffect Hook instead.

Lastly, the useRef hook is very useful, and can be helpful in building your own custom hooks! UseRef takes in a single initial value as argument, and returns a plain JavaScript object. This object will be a mutable ref object with a .current property that will be set to the value that was passed in. This object will live for as long as the component does and can be used to access the DOM. (This can be achieved by attaching the ref object to a node, where the .current property will change every time the node is updated.) It can also function as a vessel to keep any mutable data around, similar to using an instance field in a class component. The only thing to be wary of when using this Hook is to keep in mind that it will not notify you when the object is mutated and will not trigger a re-render of the component.

Building your Custom Hooks

Great! Now we are ready to jump into the world of making our own Hooks. You might be thinking, “React comes with so many built-in Hooks for different specialized actions, what do I need to make my own for?” The short answer is that these custom Hooks will allow you to remove stateful logic from one component and instead place it inside a Hook, so that you can use the same logic in several different components by simply calling the Hook —reducing redundancies and keeping things DRY. This can also save you from muddying up your component tree by reducing the need to create higher-order components just to pass on that logic.

A custom Hook will be like any other standard JavaScript function, except that best practice dictates that “use” should be placed in front of the name that you give it. Thus a hook should always be called something like “useChat” or “usePalette”; this serves as a reminder of the two cardinal rules that must be enforced for all Hooks. Apart from that, it can take in any amount of arguments and can return whatever you would like — it all depends upon your needs. It can also take in other Hooks like useState or useEffect. This newly created Hook can then be called in whatever components you would like — remembering to keep it at the top level. Do note that while stateful logic is being shared across components through this Hook, any state or effects that the Hook accesses will be limited to the specific component that the Hook is called in. Thus it cannot be used to share or mutate information across components. Nonetheless, it’s very handy to keep your code clean and organized!

Hopefully this has given you a good introduction into the world of React Hooks and will motivate you to give them a try. Once you get the hang of them, they will certainly be a boon to your apps.

--

--