hooks
1. hook
1.useState()
1). State Hook allows function components to have state state and read and write state data
2). Syntax const [fruit, setFruit] = useState(123)
3). useState() Description:
Parameter: The value specified by the first initialization is cached internally
Return value: an array containing 2 elements (xxx, setxxx), the first is the internal current state value, and the second is the function to update the state value
var ageState = useState(123); // Returns an array with two elements var age = ageState[0]; // the first value in the array var setAge = ageState[1]; // the second value in the array
4). Writing in setState() 2
setState(newValue): The parameter is a non-function value, directly specify the new state value, and use it to overwrite the original state value internally
setState(val => newVal): The parameter is a function, which receives the original state value, returns the new state value, and uses it to overwrite the original state value internally
// Multiple state variables can be declared in a component! const [xxx, setxxx] = useState(1); const [xxxx, setxxxx] = useState('222'); const [xxxxx, setxxxxx] = useState([{name:'zhangning'}]);
2.useEffect()
1). Effect Hook allows you to perform side-effect operations in function components (used to simulate declaration cycle hooks in class components)
By default it is executed after the first render and after every update
React guarantees that every time an effect is run, the DOM has been updated.
2). Side-effect operations in React:
Send ajax request data acquisition, set subscription/start timer, manually change the real DOM
3). The effect will be executed after each round of rendering, but you can choose to have it execute only when something changes.
useEffect(()=>{}) useEffect(()=>{}, []) useEffect(()=>{}, [xxx]) useEffect(()=>{ // effect Optional clear mechanism (subscription or timer ID, etc.), in order to prevent memory leaks, clear functions will be executed before the component is unloaded return ()=>{} }, [xxx])
3.useLayoutEffect()
1. Same as useEffect, it will call effect synchronously after all DOM changes
2. You can use it to read the DOM layout and trigger re-rendering synchronously. The update schedule inside useLayoutEffect is refreshed synchronously before the browser draws
4. Custom Hook
1). A custom Hook is a function that must start with use, and other Hooks can be called inside the function
// Monitor browser window size export function useWinSize() { const [size, setSize] = useState({ width: document.documentElement.clientWidth, height: document.documentElement.clientHeight }); const onResize = useCallback(() => { setSize({ width: document.documentElement.clientWidth, height: document.documentElement.clientHeight }); }, [size.width]); useEffect(() => { window.addEventListener('resize', onResize); // return means that it will only be executed when it is destroyed return () => { window.removeEventListener('resize', onResize); }; }, []); return size; } const width = useWinSize()
5.useRef()
1). Ref Hook can store, find tags or any other data in the component in the function component
2). Syntax: const refCont = useRef()
3). Function: save the label object, the function is the same as React.CreateRef()
import React, {useRef} from 'react'; import Children from './components/Children'; function Index() { const chRef = useRef(); // Access child components via current console.log(chRef.current) return ( <> <Children ref={chRef}/> </> ); } export default Index;
6.useImperativeHandle()
1. You can customize the instance value exposed to the parent component when using ref.
useImperativeHandle(ref, createHandle, [deps])
2. Use with forwardRef
// parent component function Parent() { const childRef = useRef(); return ( <div> <AllProjectTable ref={childRef}/> <button onClick={() => childRef.current.handleClick()}>aaaa</button> </div> ); } // Subassembly const Child=(props, ref)=> { const [state, setState] = useSataeO(); const handleClick = () => {}; // Methods exposed to parent components useImperativeHandle(ref, () => ({ handleClick })); return ( <> <button onClick={() => handleClick()}>dddd</button> </> ); } // Child components are wrapped by forward export default forwardRef(Child);
7.useContext()
Understanding: a way of communication between components, often used for communication between ancestor components and descendant components
1. Receive the context object and return the current value of the context. The current context value is determined by the attribute value prop of the <MyContext.Provider> closest to the current component in the upper component
2. Even if the ancestor uses React.memo or shouldComponentUpdate, it will re-render when the component itself uses useContext.
3. The component that calls useContext will always re-render when the context value changes
How to use 1. create Context container object: const MyContext = React.createContext() 2.When rendering child components, wrap the outside MyContext.Provider pass value Properties pass data to descendant components <MyContext.Provider value={data}>Subassembly</MyContext.Provider> 3.The descendant component reads the data: // The first one: only for class components, just understand const contextType = MyContext // declares the receiving context this.context // Read the value data in the context // The second: function components, class components can be used <MyContext.Consumer> { value => {// value is the value data in the context Display content } } </MyContext.Consumer>
Example
import React, {createContext, useContext} from 'react'; // Create a Context container object // When rendering child components, wrap MyContext.Provider outside and pass data to descendant components through the value attribute const MyContext = createContext({}); const {Provider, Consumer} = MyContext; function AAA() { const name = 'zhangning'; const age = 24; return ( <div> I am the ancestor component, name:{name} <Provider value={{name, age}}> <BBB/> </Provider> </div> ); } function BBB() { return <div><CCC/></div>; } function CCC() { // Here you can also use useContext to get data directly, which is more convenient and practical. // const {name} = useContext(MyContext); return <div> obtained from the ancestor component name: <Consumer> {value => {return `${value.name},age ${value.age}`;}} </Consumer> </div>; } export default AAA;
8.useReducer()
1. Equivalent to an alternative to useState, receive a reducer with (state, action)=>newState, and return the current state and its matching dispatch method.
2. In some scenarios, useReducer is more applicable, for example, the state logic is complex and contains multiple sub-values, or the next state depends on the previous state, etc. Moreover, using useReducer can also optimize the performance of components that trigger deep updates, and can pass dispatch to subcomponents instead of callback functions
const initialState = {count: 0}; function reducer(state, action) { switch (action.type) { case 'increment': return {count: state.count + 1}; case 'decrement': return {count: state.count - 1}; default: throw new Error(); } } function Counter() { const [state, dispatch] = useReducer(reducer, initialState); return ( <> Count: {state.count} <button onClick={() => dispatch({type: 'decrement'})}>-</button> <button onClick={() => dispatch({type: 'increment'})}>+</button> </> ); }
The official website does not recommend using reducer to simulate Redux…
9.useMemo()
1. Return a memoized cached value
Passing the creation function and the dependencies array as parameters to useMemo will only recalculate the memoized cache value when the dependencies change. Avoid expensive calculations on every render.
The function passed to useMemo will be executed during rendering. No dependencies, new values are calculated on every render
You can use useMemo as a performance optimization solution.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
10.useCallback()
1. Pass the callback function and the array of dependencies as parameters, and return the memoized cached version of the callback function, which will only be updated when the dependencies change.
useCallback(fn, deps) is equivalent to useMemo(()=>fu, deps)
Conceptually, all values referenced in callback functions should appear in the dependencies array.
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
2. Component optimization
1.component
First, let's take a look at the performance optimization in the class component in react, mainly focusing on the following two points
1. When setState is called, it will trigger the component to re-render, regardless of whether the state before and after changes
2. When the parent component is updated, the child component will also be updated automatically (low efficiency)
Ways to improve efficiency:
Let the component perform render() when the state or props data changes
Reason: as long as the setState method is called, shouldComponentUpdate() in the component always returns true, causing the component to render
Solutions
// Option 1: By overriding the shouldComponentUpdate() method, compare the old and new state or props, return true if there is a change, and return false if there is no change shouldComponentUpdate(nextProps, nextState) { console.log(this.props, this.state);// current props and state console.log(nextProps, nextState);// Changed props and state if (JSON.stringify(nextProps) === JSON.stringify(this.props) || JSON.stringify(nextState) === JSON.stringify(this.state)) { return false; } else { return true; } } // Option 2: Use PureComponent // PureComponent overrides sholdComponentUpdate() to return true only if state or props data changes // Note: It is only a shallow comparison of state and props data. If only the internal data of the data object has changed, return false, // Do not modify state data directly, but generate new data // The project generally uses pureComponent to optimize // Disadvantage of pureComponent: It may cause false negative judgment due to deep data inconsistency, so the result of shouldComponentUpdate returns false, and the interface cannot be updated
2. Optimized performance scheme in hooks
In functional components, shouldComponentUpdate is lost, and I decide whether to update by judging the state before and after. In functional components, react no longer distinguishes between the two states of mount and update, that is to say, each call of the functional component will execute all its internal abbreviations, which will bring a large performance loss. Here, two hooks useMemo and useCallback appear in hooks to solve the performance solution of functional components.
First look at the source code of useMemo and useCallback
function useCallback<T extends (...args: any[]) => any>(callback: T, deps: DependencyList): T; function useMemo<T>(factory: () => T, deps: DependencyList | undefined): T;
The parameter form is the same as useEffect. UseEffect is used to deal with side effects, but these two are not.
useMemo and useCallback will be executed when the component is rendered for the first time, and will be executed again when the dependency changes;
All return the cached value, useMemo returns the cached variable, and useCallback returns the cached function.
Advantages: The variables wrapped by useMemo are equivalent to caching the variables. When the parent component is re-rendered, the variable will not change == "The child component will not be re-rendered.
// useMemo example function Test() { const [count, setCount] = useState(1); const [val, setVal] = useState(''); // Sum1 refreshes the component and re-executes sum1 every time count and val change. // But the calculation of sum1 here only depends on the value of count, and there is no need to calculate sum1 when val is modified. // In this case, we can use useMemo to perform the calculation (sum2) only when the value of count is modified const sum1 = () => { console.log('sum1111'); let sum = 0; for (let i = 0; i < count; i++) { sum += i; } return sum; }; // Re-execute the calculation every time the value of count changes const sum2 = useMemo(() => { console.log('sum2222'); let sum = 0; for (let i = 0; i < count; i++) { sum += i; } return sum; }, [count]); return ( <div> <h1>{count}+++{val}+++{sum1()}+++{sum2()}</h1> <div> <button onClick={() => setCount(count + 1)}>+++</button> <input type='text' value={val} onChange={event => setVal(event.target.value)}/> </div> </div> ); }
useCallback
Why use useCallback, and the performance improvement that useCallback can bring
Similar to useMemo, it is very useful when the callback function bed is optimized and uses reference equality to avoid unnecessary rendering of child components, and it is the same as pureComponent. That is to say, when the parent component passes a function to the child component, the update of the parent component will cause the function to be regenerated and the function reference passed to the child component will change, which will cause the child component to be updated. In many cases, the update of the child component is not necessary, so the functions passed to the child components are cached through useCallback
Advantages: The function wrapped by useCallback is equivalent to caching the function. When the parent component is re-rendered, the function will not be re-defined == "The child component will not be re-rendered.
const Child = ({getNum}) => { return <h1>data:{getNum}</h1>; }; function Test() { const [count, setCount] = useState(1); const [val, setVal] = useState(''); const sum = useCallback(() => { return Array.from({length: count}, (v, i) => i).reduce((a, b) => a + b); }, [count]); return ( <div> <Child getNum={sum}/> <h1>{count}+++{val}++++{sum()}</h1> <div> <button onClick={() => setCount(count + 1)}>+++</button> <input type='text' value={val} onChange={event => setVal(event.target.value)}/> </div> </div> ); } // The above will only re-render the child component when the count changes
Summarize:
memo for wrapping child components
Whether the memo is repeated for the rendering of a component
<Header />
usememo for repeated execution of a piece of function logic
()=>{}
useEffect is done after rendering
useMemo is done during rendering (an empty array will only be executed once)
useMemo(()=>{},[])
useCallback
useMemo(()=>{fn})Equivalent to useCallback(fn)
3.Memo
memo() is similar to PureComponent, it helps us control when the component is re-rendered
The understanding is that memo helps us cache components and judge whether to re-render through the conditions of the second parameter
Example:
1. memo is not applicable, the parent component is updated, and the child component will also be updated
2. The parent component is updated. The second parameter is not applicable to the child component memo. By default, each content in pre and next is compared. The parent component does not pass any attributes to the child component, the parent component updates the attribute, and the child component does not refresh.
import React, {memo} from 'react'; import './index.scss'; const Header = memo(props => { return ( <div> header components </div> ); }); export default Header;
3. Use the second parameter of memo to compare all the properties passed from the parent component to the child component, and update if there is a change
import React, {memo} from 'react'; import './index.scss'; const Header = memo(props => { return ( <div> header components </div> ); }, (pre, next) => { const keys = Reflect.ownKeys(next); return keys.every(i => pre[i] === next[i]); }); export default Header;
4. Use the second parameter of memo to compare a certain attribute, compare all attributes passed from the parent component to the child component, and update if there is a change
import React, {memo} from 'react'; import './index.scss'; const Header = memo(props => { return ( <div> header components </div> ); }, (pre, next) => { return pre.val === next.val; }); export default Header;
three,
How to dynamically pass in a structure (label) with content like inside a component?
Vue: use slot technology, that is, pass in the structure through the component tag body
In React:
Use children props: pass in the structure through the component tag body, example 1 below
Use render props: pass in the structure through the component tag attribute, generally use the render function attribute, the following example 2
Use children props
// children props example 1 import React from 'react'; function AAA() { return ( <><BBB>hello!</BBB></> ); } function BBB(props) { return <> <h2>I'm BBB components</h2> {/*Here you can print the hello! passed from the AAA parent component and receive it through props.children*/} {props.children} </>; } export default AAA;
Using render props
// A and B components parent and child components <A render={(data)=><B data={data}></B>}></A> A Components:{this.props.render(internal state data)} B component: read A Component incoming data display {this.props.data}
// Example 2 import React from 'react'; function AAA() { return ( <> <BBB render={(name) => <CCC name={name}/>}></BBB> {/*<BBB peiqi={(name) => <CCC name={name}/>}></BBB>*/} </> ); } function BBB(props) { const name = 'zhangning'; return <> <h2>I'm BBB components</h2> {/*Call the render method, reserve a seat, place the component, and pass the name*/} {/*In the A component, use the B component, call the render method, load the subcomponent C of the B component, pass the name, which is equivalent to the slot in vue*/} {/*Here render can write any character, it can be consistent when calling, render is easy to read*/} {/*{props.peiqi(name)}*/}{/*A Also use peiqi when used in components*/} {props.render(name)} </>; } function CCC(props) { return <> <h2>I'm BBB components</h2> received B data in components name:{props.name} </>; } export default AAA;
Four, component communication
1. Relationship between components
1. Parent-child components
2. Sibling components (non-nested components)
3. Grandparent components (cross-level components)
Several communication methods: 1.props: children props render props 2.News subscription-release pubs-sub,event and many more 3.Centralized management: redux,dva 4.context producer-consumer model
A better match: Parent and child components: props Sibling component: message subscription-Release, centralized management Grandchild components: message subscriptions-release, centralized management, context(Less used for development, more used for packaging plug-ins)