With the new API for hooks added to React in v16.8.0, it is important to understand how to use it and be able to write a few custom hooks to suit our business.
1. Some common hooks
Several built-in hooks are officially provided, so let’s take a brief look at their usage.
1.1 useState: state hooks
Data that needs to be updated on the page state can be put into the useState
hook. For example, if you click a button, the data is incremented by 1.
In the typescript system, the type of count is, by default, the type of the current initial value, e.g. the variable in the above example is of type number
. If we want to customise the type of this variable, we can define it after useState
as follows.
|
|
Also, when using useState
to change state, the entire state is replaced, so if the state variable is an object
type of data and I only want to change one of the fields, it will automatically merge the data internally when setState
is called from within the previous class
component.
However, when using useState
within a function component, you need to merge the data yourself before calling the method, otherwise the fields will be lost.
|
|
1.2 useEffect: side effect hooks
useEffect can be thought of as a combination of the functions componentDidMount
, componentDidUpdate
and componentWillUnmount
.
The useEffect hook must be executed once when the component has been initialized. Whether or not the component is updated during re-rendering depends on the 2nd parameter passed in.
- when there is only one argument to the callback function, the callback is executed for each update of the component.
- when there are 2 parameters, the callback is executed only if the data in the 2nd parameter changes.
- to be executed only once when the component has been initialised, the 2nd parameter can be passed into an empty array.
We can see in this example that the useEffect callback will be executed whether the add button
or the settime button
is clicked.
|
|
If this is changed, the callback will only be output on the console when the count changes, and not when the nowtime value is changed.
The useEffect callback function can also return a function which is called before the end of the effect’s life cycle. To prevent memory leaks, the clear function is executed before the component is unloaded. Also, if the component is rendered multiple times, the previous effect is cleared before the next effect is executed.
Based on the above code, we modify it slightly.
This mechanism is particularly useful in cases where there is a need to add and remove bindings, such as listening for changes in the window size of a page, setting timers, establishing and disconnecting from a back-end websocket service, and so on. The useEffect can be wrapped again to form a custom hook, which we will talk about below.
1.3 useMemo and useCallback
The variables and methods defined in the function component are re-calculated when the component is re-rendered, as in the following example.
|
|
There are 2 buttons, one for count+1 and one to set the current timestamp. The getSun()
method calculates the sum from 1 to count, and the sum method will recalculate the sum each time we click the add button. However, when we click the settime button, the getSum method will also recalculate, which is unnecessary.
Here we can use useMemo
to modify it.
Once modified, you can see that the sum value is only recalculated when the count changes, and is not recalculated when the settime button is clicked. This is thanks to the useMemo
hook feature.
|
|
useMemo returns the value returned in the callback, and memoizedValue it is only recalculated when a dependency changes. This optimisation helps to avoid a high overhead calculation at each rendering. If an array of dependencies is not provided, useMemo would calculate the new value each time it is rendered.
In the example above, sum is only recalculated when the count variable changes, otherwise the value of sum remains the same.
useCallback is the same type as useMemo, except that useCallback returns a function, e.g.
2. Implementing a few custom hooks
In the official documentation, the online and offline functionality for friends is implemented. Here we learn to implement a few hooks ourselves.
2.1 Getting the changing width and height of a window
We get the width and height of the window in real time by listening to the resize
event, and wrapping this method to automatically unbind the resize event before the end of its life.
|
|
It is also very easy to use.
2.2 Timer useInterval
When using a timer in a front-end, it is usually necessary to clear the timer before the end of the component’s lifecycle, and if the timer’s period has changed, to clear the timer before restarting it according to the new period. The most common scenario for this is a nine-box draw, where the user clicks to start the draw, starts slowly, then gradually gets faster, the interface returns the winning result, then starts to slow down and finally stops.
It is easy to think of using useEffect
to implement such a hook (as an example of an error).
Let’s try this code in our project.
However, this runs strangely, the page goes from 0 to 1 and then never stays the same. The output of console.log(count)
indicates that the code is not stuck, so what’s the problem?
The props and states in React components can change, and React re-renders them and “discards” any results from the last rendering, so they are no longer relevant to each other.
The useEffect() Hook also ‘discards’ the previous rendering result, it clears the previous effect and creates the next effect, which locks in the new props and state, which is why our first attempt at a simple example worked correctly.
But setInterval doesn’t ’throw away’. It will keep referring to the old props and state until you replace it - you can’t do that without resetting the time.
The hook useRef is used here. We store the callback in the ref and update the value of ref.current
when the callback is updated.
|
|
When we use the new useInterval
, we find that self-incrementing is possible.
Here we use a variable to control the rate of increase.
|
|
The rate at which the count is increased can be adjusted by clicking on the two buttons separately. When you want to stop the timer, set diff to null (setDiff(null)). When it is reset to a number, the timer restarts.
3. Summary
There are a lot of interesting things you can do with the react hook, but here are just a few simple examples. We’ll get more into how hooks work later on.