A quick reference to commonly used hooks
I had a fun coding challenge recently where I had to build out a feature with React. It was definitely a nice change from a typical algorithmic coding challenge. The deliverable stated that I could only use functional components. But wait! I thought functional components couldn’t hold state. Incoming React hooks!
What are Hooks?
React hooks were introduced in 2018 as a way to give functional components, well, more functionality with state. Traditionally, state is stored and managed in class components. Code held in class components can get long and convoluted considering all of the lifecycle methods and state you might have to write. The hooks system allows us to write more reusable code rather than the inheritance nature of class components. But just remember “Hooks don’t replace your knowledge of React concepts”. They build on top of concepts like props, state, context, refs, and lifecycle.
React hooks are a native feature of
create-react-app. To use hooks, all you have to do is import React and destructure the hooks you want to use as shown in the gist below.
Commonly Used Hooks
There are ten native hooks available for use. They include:
useDebugValue. There’s also an option to write custom hooks. For custom hooks, we can abstract hooks into a function that starts with the convention “
use____”. I will talk about two common hooks below.
Some basic rules to know when using hooks are to:
- Use hooks at the top-level — meaning, don’t use them in loops, conditions, or nested functions. This is because is it possible to use many hooks in one component and the order of them matters. So we want to be able to preserve state correctly.
useState() — initialize, reference, or update state
useState is the function that lets you use and manipulate state in a functional component. It uses array destructuring to allow for use two functions to reference a piece of state and to update state. The initial value of state is passed in as an argument of
useState. A common use case would be to use the second element, the setter function, as a callback of an event handler. That setter function would be the equivalent of
setState in a class component.
In the gist below, we can compare how state would be handled in a functional and class component. One benefit of
useState is that only one line of code is necessary to do what lines 5 to 7 is doing.
useEffect() — similar to lifecycle methods like componentDidMount() or componentDidUpdate()
The next hook we’ll explore is called useEffect which is useful for actions to take when rendering and/or re-rendering. One common use case is to make requests and fetch data with
useEffect. The use of
componentDidMount is not possible in functional components. There are three scenarios to consider when using
useEffect. This hook can run code automatically when the component:
- Initially renders
- Initially renders and also whenever it re-renders
- Initially renders, whenever it re-renders as well as when data is changed
Another way to think about those three scenarios is if you want to use
useEffect with or without cleanup — meaning, do you want to express any side effects like running additional code after the initial render? If you decide to use
useEffect to handle some cleanup, you can return a callback function to be invoked on the next render. One example use case would be to return cleanup function in order to cancel the timer on
setTimeout. On the first render, the
setTimeout function would run as normal, then on the second render, it will get canceled. Pretty neat stuff!
useEffect can take a second argument of three things: nothing, an empty array, and an array with elements. It’s more than likely that you’ll either use a second arg of an array — filled or not. The second argument will run at the initial render. If there is filled array as a second arg,
useEffect will run again if the data has since been changed.
In the gist below, state is initially set to an empty array on line 3 with
setState. On line 5, we use
useEffect to fetch natively by adding an
async/await function. You can of course use other libraries like axios to handle fetching. One thing to note is that the
useEffect function itself cannot be
async, which is why, below, the
async keyword is used in
data() instead. As a second argument, we pass in the array with the
results which holds the data/state we’ve fetched and set with
One of the cool things functional components can do is hold multiple
useEffect functions. Depending on those three scenarios listed above, you can use as many hooks as needed.
Hooks are a more modern way to write React and offer so much more functionality to functional components. They are definitely worth learning and can really transform and optimize your React apps.