Preface
Hook is a new feature in React 16.8. It is completely optional and 100% backward compatible. It allows you to use function components, use class components and other features of react, such as management state, life cycle hooks, etc. Conceptually speaking, React components have always been more like functions. Hook embraces functions without sacrificing the spiritual principles of React.
advantage:
1. The code is more readable. The code logic of the original function is split into different life cycle functions, which makes it easy for developers to be unfavorable for maintenance and iteration. Function codes can be aggregated through React Hooks to facilitate reading and maintenance. For example, each life cycle often contains some irrelevant logic. Generally, we will get data in componentDidMount and componentDidUpdate. However, the same componentDidMount may also contain a lot of other logic, such as setting event listening, and then it needs to be cleared in componentWillUnmount. The code that is interrelated and needs to be modified in comparison is split, while the code that is completely unrelated is combined in the same method. This is easy to cause bugs and lead to logical inconsistencies.
2. The component tree level becomes shallow. In the original code, we often use HOC/render props and other methods to reuse the state of components, enhance functions, etc., which undoubtedly increases the number of component tree layers and rendering. After observing React applications in React DevTools, you will find that components composed of other abstract layers such as providers, consumers, advanced components, render props and other "necked hell". In React Hooks, these features can be implemented through powerful custom Hooks.
3. No need to consider this pointing issue anymore. In class components, you have to understand how this works in JavaScript.
shortcoming:
1. Responsive useEffect
When writing function components, you have to change some writing habits. You must be clear about the timing of the "dependency array" of useEffect and useCallback in your code. Sometimes, your useEffect depends on the immutability of a certain function, and the immutability of this function depends on the immutability of another function, thus forming a dependency chain. Once a node of this dependency chain is unexpectedly changed, your useEffect is accidentally triggered. If your useEffect is an idempotent operation, it may bring about performance-level problems. If it is non-idempotent, it will be bad.
Therefore, compared with componentDidmount and componentDidUpdate, useEffect brings greater mental burden.
2. The status is not synchronized
Functions are run independently, and each function has an independent scope. The variables of the function are stored in the scope of the runtime. When we have asynchronous operations, we often encounter the variable references of the asynchronous callback are the previous ones, that is, the old ones (can also be understood as closures here). For example, the following example:
import React, { useState } from "react"; const Counter = () => { const [counter, setCounter] = useState(0); const onAlertButtonClick = () => { setTimeout(() => { alert("Value: " + counter); }, 3000); }; return ( <div> <p>You clicked {counter} times.</p> <button onClick={() => setCounter(counter + 1)}>Click me</button> <button onClick={onAlertButtonClick}> Show me the value in 3 seconds </button> </div> ); }; export default Counter;
When you click Show me the value in 3 seconds, click Click me to change the counter value from 0 to 1. After three seconds, the timer fires, but alert comes out with 0 (old value), but the result we hope is the current state 1.
This problem will not occur in class component, because the properties and methods of class component are stored on an instance, and the call method is: and (). Because the value is taken from an unchanged instance every time, it is an old problem that no references exist.
In fact, you can also refer to the instance of the class to solve the hooks problem. Use the immutable RefObject returned by useRef to save the state, and then the value method changes from counter to: . as follows:
import React, { useState, useRef, useEffect } from "react"; const Counter = () => { const [counter, setCounter] = useState(0); const counterRef = useRef(counter); const onAlertButtonClick = () => { setTimeout(() => { alert("Value: " + ); }, 3000); }; useEffect(() => { = counter; }); return ( <div> <p>You clicked {counter} times.</p> <button onClick={() => setCounter(counter + 1)}>Click me</button> <button onClick={onAlertButtonClick}> Show me the value in 3 seconds </button> </div> ); }; export default Counter;
As we expect, the alert value is the current value of 1.
How to avoid FAQs about react hooks
- Don't write too many dependencies in useEffect, divide these dependencies into multiple single-function useEffects. In fact, this follows the "single responsibility model" of software design.
- If you encounter the problem of state out of synchronization, you can consider manually passing parameters to the function. like:
// The count of showCount comes from the parent scope const [count,setCount] = useState(xxx); function showCount(){ (count) } // The count of showCount comes from the parameter const [count,setCount] = useState(xxx); function showCount(c){ (c) }
But this can only solve some problems. Many times you have to use the above useRef solution.
3. Pay attention to the warnings of the eslint-plugin-react-hooks plugin.
4. When you are in complex business, use Component instead of hooks.
The above is a detailed explanation of the advantages and disadvantages of React hooks. For more information about the advantages and disadvantages of React hooks, please pay attention to my other related articles!