Hooks are by far the most popular feature introduced in version 16.8 of React. They are functions that bring React class component features, like using state, to functional components. Hooks also bring a more ergonomic look to functional components, making their structure a little clearer compared to the class-based components.
There are a total of 10 different hooks available in React. We will explore some of the most common ones and develop our own custom hook. The code examples from this post are all available in our Lola Lab repository: cookie clicker component and custom window dimensions hook.
Before we get started
The useState() hook is probably the most important hook React is currently offering. It returns an array with two values: the first value is always going to be our state, and the second is a function that updates that state.
We can also pass a value in the useState hook – it will be the default value for our state. The magic of this hook is that every time the state is updated, the component using that state will automatically rerender with the new value. A good example would be the Cookie Clicker game we recreated here.
useEffect() compels a component to do something specific after a render: fetching data, directly updating the DOM, setting a timer, etc. We can use this hook to get an alert letting us know that we have clicked the cookie every time we reach an odd number of clicks. This works because after a click our state changes, the page gets rerendered, our hook gets triggered and it checks for an odd value and alerts when it finds one:
We can also pass a dependency array to the hook - this will affect how many times it will run. If we don’t pass a dependency array, it will run on every render; on an empty dependency array, it will run on the first render, and if we pass some state value in it, it will run every time that state value updates.
useContext() allows you to work with React Context API, which lets you share data throughout the entire component tree. This hook also has the advantage of easily sharing the same data over different disconnected components and avoiding props chaining.
For example, if we create a new Context for the user and wrap the components in which we want to consume that user data in a Provider, we’re going to be able to use all of that data in the wrapped components.
The useRef() hook allows you to create a mutable object that will keep the same reference between renders. It is similar to useState, but it does not trigger a rerender. A common use case for this is grabbing HTML elements from the DOM by passing an element a ref attribute that can be referenced in a function, and it can be used to set focus, scroll to the referenced element, or any other native DOM action.
useReducer() is a hook used for state management with Redux. Instead of updating the state directly some actions are dispatched to a reducer function that determines how to compute the next state. Redux is a little more complex and out of the scope of this article, but here is a great video by DevEd about it (directs to YouTube).
Let’s also mention the more uncommon hooks that React offers:
Speaking of custom hooks, let’s now create one of our own.
Let’s create one and put it to work. We want to implement a hook that will always get the right Window width and height, even after a window resize.
With the help of the getWindowDimensions() function, we are able to get the initial window size. We are setting that in our state and we are adding an event listener for the handleResize function to be triggered every time we resize our browser window. And that is it - we have a hook that can be imported and used in any component. Check it out here.
Hooks are fun and they really make a difference when using functional components. All the examples above are available to check on our Lola Lab site and repository. And, of course, you can read all about React hooks on the reactjs.org website.