preface
React-hooks are new in React 16.8. It allows us to use state, lifecycle, and other React features in function components, not just class components. React-hooks this article takes you through the heart of writing react-hooks, which I hope will impress you on the screen.
useState
UseState returns an array: a state, and a function to update the state.
UseState is similar to the this.setstate of the class component, but it does not merge the new state with the old state, instead replacing it directly
Note that:
UseState (0), useState({a:), useState({a:); 1}), useState([1, 2]), also allows us to pass in a function that logically calculates the default value
There are also two ways to update a state when it needs to be updated: one is to update it with a new state value, and the other is to return the new state with a functional update
// Let hookStates = []; // index let hookIndex = 0; Function useState(initState) {if (typeof initState === "function") {hookStates[hookIndex] = initState(); } else { hookStates[hookIndex] = hookStates[hookIndex] || initState; } // Use closure to maintain function call position let currentIndex = hookIndex; Function setState(newState) {if (typeof newState === "function") {// copy the prevState to newState newState = newState(hookStates[currentIndex]); } // Update state hookStates[currentIndex] = newState; // Render (); } return [hookStates[hookIndex++], setState]; }Copy the code
useEffect
UseEffect is an Effect Hook that gives function components the ability to manipulate side effects. It serves the same purpose as componentDidMount, componentDidUpdate, and componentWillUnmount in the Class component, but has been consolidated into an API. Unlike componentDidMount or componentDidUpdate, effects scheduled with useEffect do not block the browser update view, making your application seem more responsive.
Note the role of the second parameter in useEffect:
UseEffect is called every time the component render without passing anything
Pass an empty array [] and useEffect is called only once
Pass in a non-empty array containing variables, and useEffect is executed only if those variables change
// Let hookStates = []; // index let hookIndex = 0; function useEffect(callback, Remote construction, remote construction, remote construction, remote construction, remote construction, remote construction, remote construction, remote construction, remote construction, remote construction. Run, run, run, run, run, run, run, run, run, run If (typeof item === "object" && typeof item! == "function" && item ! == null ) { return isObjectValueEqual(item, lastdependiencies[i]); } else { return item === lastdependiencies[i]; }}); if (same) { hookIndex++; } else { hookStates[hookIndex++] = dependiencies; callback(); }} else {// initial call to hookStates[hookIndex++] = dependiqueues; callback(); }} / / compare two objects are consistent function isObjectValueEqual (a, b) {var aProps = Object. GetOwnPropertyNames (a); var bProps = Object.getOwnPropertyNames(b); if (aProps.length ! = bProps.length) { return false; } for (var i = 0; i < aProps.length; i++) { var propName = aProps[i]; var propA = a[propName]; var propB = b[propName]; // no propName in b if (! b.hasOwnProperty(propName)) return false; If (propA instanceof Object) {if (this.isObjectValueEqual(propA, PropB)) {} else {return false; } } else if (propA ! == propB) { return false; } else { } } return true; }Copy the code
useMemo
UseMemo passes in the creation of functions and an array of dependencies as arguments, and it recalculates memoized values only when a dependency changes. This optimization helps avoid costly calculations every time you render.
Note the role of the second parameter in useMemo:
No array is passed, every update is recalculated
An empty array is evaluated only once
Depending on the corresponding value, when the corresponding value changes, will be recalculated
// Let hookStates = []; // index let hookIndex = 0; Function useMemo(factory, dependencies) {if (hookStates[hookIndex]) { lastDependencies] = hookStates[hookIndex]; Run, run, run, run, run, run, run, run, run, run If (typeof item === "object" && typeof item! == "function" && item ! == null ) { return isObjectValueEqual(item, lastdependiencies[i]); } else { return item === lastdependiencies[i]; }}); if (same) { hookIndex++; return lastMemo; } else {// Let newMemo = factory(); hookStates[hookIndex++] = [newMemo, dependencies]; return newMemo; }} else {// first call let newMemo = factory(); hookStates[hookIndex++] = [newMemo, dependencies]; return newMemo; Function isObjectValueEqual(a, b) {... }Copy the code
useCallback
UseCallback takes an inline callback function parameter and an array of dependencies (the child depends on the parent’s state, that is, the child uses the parent’s value). UseCallback returns the Memoized version of the callback function, which is updated only when a dependency changes
UseCallback passes the creation of functions and an array of dependencies as arguments to useMemo, which recalculates memoized values only when a dependency changes. This optimization helps avoid costly calculations every time you render.
Note the role of the second parameter in useCallback:
No array is passed, every update is recalculated
An empty array is evaluated only once
Depending on the corresponding value, when the corresponding value changes, will be recalculated
// Let hookStates = []; // index let hookIndex = 0; Function useCallback(callback, dependencies) {if (hookStates[hookIndex]) { lastDependencies] = hookStates[hookIndex]; Run, run, run, run, run, run, run, run, run, run If (typeof item === "object" && typeof item! == "function" && item ! == null ) { return isObjectValueEqual(item, lastdependiencies[i]); } else { return item === lastdependiencies[i]; }}); if (same) { hookIndex++; return lastCallback; } else {hookStates[hookIndex++] = [callback, dependencies]; return callback; }} else {// call hookStates[hookIndex++] = [callback, dependencies]; return callback; Function isObjectValueEqual(a, b) {... }Copy the code
memo
The Memo is similar to PureCompoent, which is used to optimize component performance and prevent components from triggering rerenders. The Memo is based on whether a component’s rendering is repeated
function memo(OldFunComp) {
return class extends React.PureComponent {
render() {
return <OldFunComp {...this.props} />;
}
};
}
Copy the code
useContext
UseContext receives a context object (the return value of React. CreateContext) and returns the current value of that context useContext(MyContext), It just allows you to read the value of the context and subscribe to changes in the context. You still need to use < myContext.provider > in the upper component tree to provide context for the lower component.
function useContext(context) { return context._currentValue; } // Parent const CountCtx = react.createcontext (); function ParentComp() { const [state, setState] = React.useState({ number: 0 }); return ( <CountCtx.Provider value={{ state, setState }}> <Child /> </CountCtx.Provider> ); Function Child() {let {state, setState} = useContext(CountCtx); return ( <div> <p>{state.number}</p> <button onClick={() => setState({ number: state.number + 1 })}> add </button> </div> ); }Copy the code
useRef
UseRef returns a mutable ref object whose current property is initialized as the parameter passed in. The ref object returned by useRef remains constant throughout the life of the component, that is, every time a function component is rerendered, The ref object returned is the same (note the use of react. createRef, which recreates the ref each time the component is rerendered)
let lastRef;
function useRef(value) {
lastRef = lastRef || { current: value };
return lastRef;
}
Copy the code
useReducer
The useReducer accepts the reducer of type (state, action) => newState and returns the current state paired with the Dispatch method. The Reducer in useReducer and Redux is like the reducer in useState
// Let hookStates = []; // index let hookIndex = 0; function useReducer(reducer, initState) { hookStates[hookIndex] = hookStates[hookIndex] || initState; let currentIndex = hookIndex; function dispatch(action) { hookStates[currentIndex] = reducer ? reducer(hookStates[currentIndex], action) : action; // Trigger view update render(); } return [hookStates[hookIndex++], dispatch]; } function useState(initState) {return useReducer(null, initState); }Copy the code
Hook usage rules
Two rules must be followed when using Hooks:
Hooks can only be called in the first layer of code, not in loops, conditional branches, or nested functions.
Hooks can only be called from Function Component or custom Hooks, not from normal JS functions.