What is React Hooks?
It is a new feature that was added to ReactJS with version 16.8 that allows you to use functional components to achieve the same results as with class-based components. In previous versions of React, for example, you will need to use class-based components if you wanted to use states or life cycle methods (the two main reasons of using class-based components in the past), but with React Hooks, it is now possible to do the same with functional components!
To start using Hooks, it is as simple as adding one line of code:
import React, { useState, useEffect } from 'react';
Let's go over a two of the more important Hooks and touch on custom Hooks rather briefly.
useState
This Hook is essentially used to replicate this.state and this.setState in class-based components. In other words, managing states. useState will always return a list of two elements, the current state value and a function that lets you update it respectively. A common convention is to use array destructuring. For example:
const [state, setState] = useState('initial state')
The setState function is similar to this.setState in a class, except it doesn’t merge the old and new state together. To illustrate this. Consider the following example:
const [state, setState] = useState({loaded: false, hello: "Hello World!"})
const loaded = () => {
setState({ loaded: true })
};
What is state.hello now? It's undefined... The proper way to update the state so that it mimics this.setState would be as follows:
const [state, setState] = useState({ loaded: false, hello: "Hello World!" })
const loaded = () => {
setState({ ...state, loaded: true })
};
useEffect
Used to effectively replace the componentDidMount life cycle method in functional components. It does so by taking in a function as an argument, which will be executed after the component has been rendered.
Although this seem to do exactly what componentDidMount does, it is quite different in a sense that it actually runs more frequently than its class-based counterpart. Specifically, it runs whenever a component is re-rendered. So when does a component get re-rendered? Well, when there is a props or state change. You can manage this by passing in a second argument (i.e., an array of variables) that tells React to execute the function if any of the variable's value in the array changed.
useEffect(() => {
/* code here will be executed after the component has been rendered AND
every time there is a props or state change */
})
Therefore, useEffect with a function as its first argument and an empty array as a second argument is identical to componentDidMount
useEffect(() => {
/* code here will be executed only after the component has been rendered */
}, [])
As you can probably guess at this point, useEffect also replaces the componentDidUpdate and componentWillUnmount life cycle method.
ComponentDidUpdate Equivalent in Hooks
useEffect(() => {
/* code here will be executed when the value of "someValue" is updated */
return () => { /* clean up code can be written here */ }
}, [props.someValue])
ComponentWillUnmount Equivalent in Hooks
useEffect(() => {
return () => { /* code here will be executed when the component will unmount */ }
}, [])
Custom Hooks
Generally, we would want to reduce code and find ourselves wanting to reuse stateful logic between components. Creating your custom Hooks enables you do just this!
Before creating our own Hooks, it is important to know some rules that are imposed on them:
- Hooks should only be called at the top level. This means that it shouldn't be called inside loops, conditions, or nested functions. Therefore, calling a Hook inside a function you passed in to useEffect, for example, is a NO
/* DON'T DO THIS! */
useEffect(() => {
useCustomHooks();
})
By convention, you should also name your Hook by prepending "use" and with a custom name in CamelCase.
- Call Hooks only from React function components, and not from regular JavaScript functions. However, it is fine to call Hooks in your own custom Hooks.
Besides following the rules, it is fairly straightforward to create and use your own custom Hooks. An example from the official React Hooks documentation is shown below.
import React, { useState, useEffect } from 'react';
function useFriendStatus(friendID) {
const [isOnline, setIsOnline] = useState(null);
function handleStatusChange(status) {
setIsOnline(status.isOnline);
}
useEffect(() => {
ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
return () => {
ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
};
});
return isOnline;
}
Some points to note as you read the example:
- Calling useState and useEffect in your custom Hooks is totally fine
- A return value is allowed as well (in fact you probably have one), in the above case, it is a single variable called isOnline but an array is allowed as well (e.g., [isOnline, setIsOnline])
And that's all folks! Hopefully, this would help you understand Hooks better. Even if you prefer the old way, I think it's still important to at least know how to read and understand projects that are using Hooks.