Hooks
Hooks are a new feature in Act 16.8 that allows you to use state and other features without writing classes.
motivation
- Reusing state logic between components is difficult
- Complex components become difficult to understand
- incomprehensible
class
Hooks
The rules
- Only used at the top level
Hooks
Do not reuse ‘in looping/conditional/nested functions - Only in the
React
Call from a functionHooks
The difference between function components and class components
The function component can capture the values used for the current rendering.
Click to see examples
For a class component, although this is immutable, this is mutable. When we render the component, this changed, so this.props changed. So this. ShowMessage gets the latest props value.
For function components it captures the values used for rendering. This feature is also used on state when using hooks.
Click to see examples
const showMessage = () = > {
alert("Write:" + message);
};
const handleSendClick = () = > {
setTimeout(showMessage, 3000);
};
const handleMessageChange = (e) = > {
setMessage(e.target.value);
};
Copy the code
If we want to get out of the ‘function component captures the value used for the current rendering’ feature, we can use ref to track some data. Current to get the latest value
const showMessage = () = > {
alert("Write:" + ref.current);
};
const handleSendClick = () = > {
setTimeout(showMessage, 3000);
};
const handleMessageChange = (e) = > {
setMessage(e.target.value);
ref.current = e.target.value;
};
Copy the code
useEffect
UseEffect can perform side effects (data fetch/involving subscriptions) in function components, UseEffect is a componentDidMount/componentDidUpdate/componentWillUnMount
- The first argument is a
callback
To return todestory
.destory
As the next onecallback
Call before execution to clear the last timecallback
Side effects - The second argument is a dependency, an array that can have multiple dependencies. Dependency changes, perform the previous one
callback
The returneddestory
, and implement neweffect
The first parametercallback
For useEffect execution, the React processing logic is called asynchronously. The callback for each effect will be placed in the task queue like the setTimeout callback function, and will be executed after the main thread is completed. So the effect callback does not block the browser from drawing the view
- Associated lifecycle replacement schemes
- ComponentDidMount Alternative
React.useEffect(() = >{
// Request data, event listener, DOM manipulation}, [])//dep=[], only executed during initialization
UseEffect captures props and state, so even in the callback function we get the original props and state */
Copy the code
componentDidUnmount
alternative
React.useEffect(() = >{
/* Request data, event listener, manipulate DOM, add timer, delay timer */
return function componentWillUnmount(){
/* Remove event listener, clear timer, delay timer */
}
},[])/* dep = [] */
UseEffect The return value of the first function can be used as componentWillUnmount
Copy the code
componentWillReceiveProps
alternative
Actually both execution time is completely different, one in the render phase, a in the commit phase, initialization useEffect will perform a, but componentWillReceiveProps will only update when props change
React.useEffect(() = >{
console.log('componentWillReceiveProps props changes:)
},[ props ])
Copy the code
componentDidUpdate
alternative
UseEffect and componentDidUpdate are executed asynchronously, while componentDidUpdate is executed synchronously, but both are in the COMMIT phase
React.useEffect(() = >{
console.log('Component update completed: componentDidUpdate')})// With no deP dependency and no second argument, this effect is executed every time the function component executes.
Copy the code
- in
useEffect
What needs to be handled in []
React React
Only if the function (and the function it calls) doesn’t reference props, state, and the values derived from them can you safely omit them from the dependency list. Use eslint-plugin-react-hooks to help validate our code
Click for a detailed example
function Counter() {
const [count, setCount] = useState(0);
useEffect(() = > {
const id = setInterval(() = > {
setCount(count + 1);
}, 1000);
return () = > clearInterval(id); } []);return <h1>{count}</h1>;
}
// Only one update will be made, and then the timer will stop running
Copy the code
- Should I think of the function as
effect
The dependence of
const loadResourceCatalog = async() = > {if(! templateType)return
const reqApi = templateType === TEMPLATE_TYPE.STANDARD ? 'listCatalog' : 'getCodeManageCatalog'
const res: any = await API[reqApi]()
if(! res.success)return
setCatalog(res.data)
}
useEffect(() = > {
loadResourceCatalog();
}, [])
The loadResourceCatalog function uses a state such as templateType
// During development, you might forget that the loadResourceCatalog function depends on the templateType value
Copy the code
The first simple solution, for some functions that are only used in useEffect, is to define effect directly so that you can rely directly on some states
useEffect(() = > {
const loadResourceCatalog = async() = > {if(! templateType)return
const reqApi = templateType === TEMPLATE_TYPE.STANDARD ? 'listCatalog' : 'getCodeManageCatalog'
const res: any = await API[reqApi]()
if(! res.success)return
setCatalog(res.data)
}
loadResourceCatalog();
}, [templateType])
Copy the code
If we needed to use the function we defined in many places, couldn’t put the definition in the current effect, and put the function in a second dependent parameter, the code would go into an infinite loop. This is because the function returns a new reference on each render
const Template = () = > {
const getStandardTemplateList = async() = > {const res: any = await API.getStandardTemplateList()
if(! res.success)return;
const { data } = res;
setCascaderOptions(data);
getDefaultOption(data[0])
}
useEffect(() = >{
getStandardTemplateList()
}, [])
}
Copy the code
In this case, if the current function does not refer to any value within any component, it can be defined outside the component so that the function reference does not change again each time the component renders.
const getStandardTemplateList = async() = > {const res: any = await API.getStandardTemplateList()
if(! res.success)return;
const { data } = res;
setCascaderOptions(data);
getDefaultOption(data[0])}const Template = () = > {
useEffect(() = >{
getStandardTemplateList()
}, [])
}
Copy the code
If the current function references some state values within the component, you can wrap the current function with useCallBack
const loadResourceCatalog = useCallback(async() = > {if(! templateType)return
const reqApi = templateType === TEMPLATE_TYPE.STANDARD ? 'listCatalog' : 'getCodeManageCatalog'
const res: any = await API[reqApi]()
if(! res.success)return
setCatalog(res.data)
}, [templateType])
useEffect(() = > {
loadResourceCatalog();
}, [loadResourceCatalog])
// With the useCallback package, if templateType remains unchanged, loadResourceCatalog will also remain unchanged, so useEffect will not be rerun
// If templateType changes, loadResourceCatalog also changes, so useEffect is re-run
Copy the code
useCallback
React React
useCallback(fn, deps)
Returns a Memoized callback function that is updated only when a dependency changes
import React, { useCallback, useState } from "react";
const CallBackTest = () = > {
const [count, setCount] = useState(0);
const [total, setTotal] = useState(0);
const handleCount = () = > setCount(count + 1);
//const handleCount = useCallback(() => setCount(count + 1), [count]);
const handleTotal = () = > setTotal(total + 1);
return (
<div>
<div>Count is {count}</div>
<div>Total is {total}</div>
<div>
<Child onClick={handleCount} label="Increment Count" />
<Child onClick={handleTotal} label="Increment Total" />
</div>
</div>
);
};
const Child = React.memo(({ onClick, label }) = > {
console.log(`${label} Child Render`);
return <button onClick={onClick}>{label}</button>;
});
export default CallBackTest;
Copy the code
Click for a detailed example
React.memo is a new property introduced in React16.6. The memo is a shallow comparison between the props and the next props to determine whether the current props are the same. If you’ve used the class component approach, then you know that memo is just like the React.PureComponent in the class component, except that memo is used in the function component. UseCallback and React. Memo must be used together to be effective.
Usage scenarios
- As a
props
To avoid unnecessary rendering of child elementsReact.Memo
Use, otherwise meaningless - As a
useEffect
You only need to add them when you need to compare themuseCallback
useMemo
React React
Returns an memoized value
Memoized values are recalcitated only when a dependency changes. This optimization helps to avoid costly computations on every render. UseCallback (fn, DEps) is equivalent to useMemo(() => fn, deps). It’s basically similar to useCallback, but slightly different
Usage scenarios
- Avoid costly calculations every time you render
Both hooks are built into React for a specific reason:
1. Reference equality
When you define an object in the React function component, it doesn’t refer to the same object as the last time it was defined (even though it has all the same values and properties).
- Depend on the list
React.memo
Most of the time, you don’t need to worry about optimizing unnecessary re-renders because optimization always comes with a cost.
- Expensive calculation
A function that computes values synchronously at high cost
conclusion
This article introduces hooks generation motivation, the difference between function components and class components, useEffect/useCallback/useMemo, etc. The life cycle replacement scheme of useEffect and whether function is used as the second parameter of useEffect are introduced.
Refer to the link
When to useMemo and useCallback
How to fetch data with React Hooks
A Complete Guide to useEffect
How Are Function Components Different from Classes?
UseCallback, useMemo analysis & differences