React Hook introduction and use

Hook Profile

Hook is a new feature React 16.8. It allows us to use the state as well as other React characteristics without writing class is. The main hook is to enhance the performance, because our pages is actually a tree (DOM tree), the tree has many branches node, a node if any changes are re-rendering performance is extremely unfriendly tree, hook is to solve this problem of.

Note : hook function is only applicable to the component, the component is not suitable for class (class components have PureComponent performance optimization for our use)

memo

React.memoFor the higher-order components . This method is used to react to optimize performance, it React.PureComponentis very similar, but it applies to a function component, but not to the component class. If our function component rendering the same result given the same props, then we can wrap it in the React.memocall, in order to render results memory module way to improve the performance of the assembly. This means that in this case, React skips the rendering operation of the components and the direct reuse results of the last rendering.

React.memoThe change affects only the props. If the function component is React.memowrapped, and its implementation have useStateor useContextthe Hook, when the context changes, it will re-render.

It will only do superficial comparison of complex objects by default, if you want to control the matching process, then please defined function is achieved by the second argument passed;

For example:

export default () => {

    const [a, setA] = useState(1)
    const [b, setB] = useState(2)

    const updateA = () => setA(3)
    const updateB = () => setB(4)

    return <div>
        <Show data={a} onClick={updateA} />
        <Show data={b} onClick={updateB} />
    </div>
}

//show组件
export default({ data = "show", onClick = () => console.log("click") }) => {
        console.log("in update", data);
        return (
            <div>
                <p>{data}</p>
                <button onClick={onClick}>修改</button>
            </div>
        )
    }

We like the components that we want to achieve two separate update and rendering values ​​of a and b, but following this component can not be achieved, because whether or b alone after a change in value due to the ratio of each react and updateA updateB method returns changed every time the comparison result is false (different), corresponding state value, so that the entire assembly will re-rendered.

So we can be achieved by introducing a partial update React.memo way to optimize performance. Show optimized components as follows:

import React, { memo } from "react";

export default memo(
    ({ data = "show", onClick = () => console.log("click") }) => {
        console.log("in update", data);
        return (
            <div>
                <p>{data}</p>
                <button onClick={onClick}>修改</button>
            </div>
        )
    },//下面是memo的第二个参数
    (prev,next)=>{
        if(prev.data === next.data){
            return true
        }
        return false
    }//如果两次传入的data相等,返回true,不会更新,相反返回false,更新组件
)

Note memo the second parameter is a callback function If you do not pass the second function, memo will default on its own once more this time to judge passed in props one by comparison. If we need to judge for themselves, they need to pass this callback.

** Note: ** class components and shouldComponentUpdate()different approach is, if props are equal, areEqualwill return true; if props are not equal, returns false. This is shouldComponentUpdatethe return value opposite.

useMemo

Of course, the above problem for repeated updating of us out there are other solutions, React provided useMemo called the hook, it was easy to use, such as the above problem is due to the fact each react to each specific method updateA and updateB It will return different, so we can use our custom useMemo be cached method:

If memo components above show the way we did not pass the second argument, will still result in the formation of excess refresh, then we can use the method cache useMemo our custom method in the parent form of:

export default () => {
    const [a, setA] = useState(1)
    const [b, setB] = useState(2)

    const updateA = useMemo(() => {
        console.log("usememo");   
        return () => setA(3)
    },[])
    const updateB = useMemo(() => {
        console.log("usememo");   
        return ()=>{setB(4)}
    },[])

    return <div>
        <Show data={a} onClick={updateA} />
        <Show data={b} onClick={updateB} />
    </div>
}

//show组件
export default memo(
    ({ data = "show", onClick = () => console.log("click") }) => {
        console.log("in update", data);
        return (
            <div>
                <p>{data}</p>
                <button onClick={onClick}>修改</button>
            </div>
        )
    }
)

This way can achieve the same a and b, respectively refresh interference.

** But now a new problem again: ** For example, if we need to value a value of +1 and b are each on a basis, we might naturally think of can be returned useMemo value fixed by setA (3) changed setA (a + 1), but the implementation of it is not the case, because useMemo role has always been our way up the package cache to avoid unnecessary refresh affect the performance of established, we when performing the first function, a is is initialized to 1, updateA function returns setA (a + 1) is setA (2), while the function useMemo setA (2) cache and awaiting behind the use of, so as to modify when the button is clicked, a value is modified to a + 1 is 2, but when the second call is supposed to be setA (3), but due to the last call has been cached setA (2) so turn setA (2) returns to the entire assembly, so every time setA (1 + 1) when the call is setA (2), and therefore the value of a change will not change after the first .

** Solution: ** useMemo pass a second parameter a, meaning that react ash to determine whether this value is changed according to the parameters passed, and if the incoming value changes, this function will be re-return (re-run updateA function), this way the above requirements can be achieved: the value a and value b are each at a basis +1;

Code:

const updateA = useMemo(() => {
        console.log("usememo");   
        return () => setA(a+1)
    },[a])   //通过判断传入的a是否变化来决定是否重新返回和缓存
    const updateB = useMemo(() => {
        console.log("usememo");   
        return ()=>{setB(b+1)}
    },[b])	//通过判断传入的b是否变化来决定是否重新返回和缓存

useCallback

useCallback and useMemo function is very similar , the difference between them is the first argument useMemo pass is pass a callback function, but it caches the return value of the function rather than the entire function, and is the first cache useCallback a parameter setting, the code is more concise, we need this function if there are other things to do rather than just caching, use useMemo, if we only need to cache a method, using useCallback more concise; here we can update and updateB method useCallback cached code:

const updateA = useCallback(()=>setA(a+1),[a])
const updateB = useCallback(()=>setB(b+1),[b])

useReducer

import React, { useState, useReducer, useCallback } from "react";
import Title from "./title";
import Ibutton from "./Ibutton";

const options = {
    add:"ADD",
    dec:"MINUS"
}

export default () => {
    //reducer默认接收两个参数,action是一个描述对象,用来描述用户针对状态state的操作行为
    //action对象有一个type属性,用来描述用户行为的类型,固定属性,不能自己命名
    const reducer = (state, action) => {//通过action.type来判断用户是什么操作,并且做出相应的操作
        const {add,dec} = options;
        switch (action.type) {
            case add:
                return state + 1;
            case dec:
                return state - 1;
            default:
                return state;
        }
    }

    const [count, dispatch] = useReducer(reducer, 20) //把处理器交给useReducer来执行,0是初始值
    //用户触发reduce人执行
    const add = useCallback( ()=>{dispatch({type:options.add})},[])

    const dec = useCallback( ()=>{dispatch({type:options.dec})},[])
    
    return (<div>
        <Title count={count} />
        <Ibutton onClick={add} name="+" />
        <Ibutton onClick={dec} name="-" />
    </div>)

}

//Title组件
import React, { memo } from "react";
export default memo((props) => {
    return (
        <h1>{props.count}</h1>
    )
})
//Ibutton组件
import React from "react";
export default (props) => {
    return <button onClick={props.onClick}>{props.name}</button>
}

Analysis Code: useReducer is useState alternative. This method takes a form such as (state, action) => newStatethe reducer, and return to the current state and its supporting dispatchmethod; we define a function reducer;

const reducer = (state, action) => {
}
const [count,dispatch] = useReducer(reducer,0)

useReducer method (Processor) The first parameter is the method of operating state, the second parameter is the default value of this state, the method may return an array, the first and second terms, respectively, and the count value of the state dispatch , users triggered by dispatch reducer processor to update the State , dispatch parameter passed is the user's type of operation, that is, action parameters reducer function, we can get them through an array of Deconstruction.

Code above defined reducer function, receiving two default parameters, Action is a description of the object, for the user to describe the state of the operation state of behavior, action object has a type attribute is used to describe the type of user behavior, this state is treated value processing needs , fixing property, not their names;

We also define two stars and add method, and cached by useCallback, outside options defined object to store a user's operation, according to a user's operation is determined to action.type then changes state to a corresponding state value operation, to achieve and we need to change the status value sufficient to consider such an operation performance.

Custom hook

Mentioned above are React hooks available to us to use, in fact React also provides us with a custom hook method of operation, such as a custom hook to reconstruct useReducer project we used above, in order to strengthen the practice and custom hook understanding;

** Note: ** hook our custom built-in hook must React same in naming such useCount and so on;

Let's create a new defineHook.js file to create our useCount this custom hook;

import { useReducer, useCallback } from "react";

const options = {
    add: "ADD",
    dec: "MINUS"
}

export const useCount = () => {
    const reducer = (state, action) => {//通过action.type来判断用户是什么操作,并且做出相应的操作
        const { add, dec } = options;
        switch (action.type) {
            case add:
                return state + 1;
            case dec:
                return state - 1;
            default:
                return state;
        }
    }

    const [count, dispatch] = useReducer(reducer, 20) //把处理器交给useReducer来执行,0是初始值
    //用户触发reduce人执行
    const add = useCallback(() => { dispatch({ type: options.add }) }, [])

    const dec = useCallback(() => { dispatch({ type: options.dec }) }, [])

    return [count, { add, dec }]

}   

Then the hook and use a direct reference to the formation of the parent

import React from "react";
import Title from "./title";
import Ibutton from "./Ibutton";
import {useCount} from "./defineHook"

export default () => {
    const [count, {add,dec}] = useCount() //把处理器交给useReducer来执行,0是初始值
    return (<div>
        <Title count={count} />
        <Ibutton onClick={add} name="+" />
        <Ibutton onClick={dec} name="-" />
    </div>)
}
Published 18 original articles · won praise 0 · Views 259

Guess you like

Origin blog.csdn.net/Joey_Tribiani/article/details/104488586