Interviewer, please don't ask me hook again

I. Preface
Let's ask you a few questions first. These questions are really asked by me in the interview. If they are true, I won't be able to correct them

What are the advantages of writing hooks over writing class components?
How do we encapsulate a hook?
What is the hooks principle?
Although the interview is cold, we still have to continue our study 😭

Second, learn more about hooks
useState
use
useState is easy to use 🙉, After a sentence, an array is returned. The value of the array is the current state and the function that updates the state; The parameter of useState is a variable, object or function. The variable or object will be used as the initial value of state. If it is a function, the return value of the function will be used as the initial value.

Batch update
Look at the following code

function Count(){

let [count,setCount] = useState(0)
const handleAdd = function(){
    setCount(count+1)
    setCount(count+1)
}
return(
    <div>
        <p>{count}</p>    
        /*Add 1 per click*/
        <button onClick={handleAdd}>add one-tenth</button>
    </div>
)

}
Copy code
In the same event, the count will not be increased twice because setCount is called twice. Imagine that if setCount is called every time in the same event, the setCount component will be rendered again every time setCount is called, which undoubtedly has a great impact on performance; In fact, if the modified state is the same, the new state in the last setCount function will overwrite the previous state

useEffect && useLayoutEffect
use
The two hook s have the same usage. The first parameter is the callback function, and the second parameter is the array. The content of the array is the dependency deps. After the dependency is changed, the callback function is executed; Note that each rendering of the component will be executed once by default. If the second parameter is not passed, the callback function will be triggered as long as the state of the component changes. If an empty array is passed, it will only be executed once during initialization. In addition, if a function is returned with return, the component will execute the function before calling the callback function every time it re renders.

difference
On the surface, the difference between the two hooks is that the execution time is different. The callback function of useEffect will be executed after the page is rendered; useLayoutEffect is executed before the page is rendered. In fact, React handles the two hooks differently. useEffect is an asynchronous call, while uselayouteeffect is a synchronous call.
When to use useEffect and when to use uselayouteeffect?
My understanding is that, depending on the situation, if the callback function will modify the state to cause the component to re render, you can use layouteeffect, because using useEffect may cause the page to flicker; If the callback function requests data or js takes too long to execute, it is recommended to use useEffect; Because at this time, the browser rendering is blocked with uselayouteeffect.

useMemo && useCallback
These two hooks can be used for performance optimization to reduce repeated rendering of components; Now let's see how these two magical hooks work.

uesMemo
function MemoDemo() {

let [count, setCount] = useState(0);
let [render,setRender] = useState(false)
const handleAdd = () => {
    setCount(count + 1);
};
const Childone = () => {
    console.log("The sub component is re rendered");
    return <p>Sub assembly I</p>;
};
const Childtwo = (props) => {
    return (
        <div>
            <p>Sub assembly II</p>
            <p>count The value of is:{props.count}</p>
        </div>
    );
};
const handleRender = ()=>{
    setRender(true)
}
return (
    <div style={{display:"flex",justifyContent:'center',alignItems:'center',height:'100vh',flexDirection:'column'}}>
        {
            useMemo(() => {
                return <Childone />
            }, [render])
        }
        <Childtwo count={count} />
        <button onClick={handleAdd}>increase</button>
        <br/>
        <button onClick={handleRender} >Sub component I rendering</button>
    </div>
);

}
Copy code
The child component will not be re rendered until render is changed

Incidentally, React.memo, the components wrapped with React.memo will be shallow compared with props and the old props every time they are rendered. If there is no change, the components will not be rendered; Examples are as follows

const Childone = React.memo((props) => {

console.log("The sub component is re rendered",props);
return <p>Sub assembly I{props.num}</p>;

})
function MemoDemo() {

let [count, setCount] = useState(0);
let [render,setRender] = useState(false)
let [num,setNum] = useState(2)
const handleAdd = () => {
    setCount(count + 1);
};

const Childtwo = (props) => {
    return (
        <div>
            <p>Sub assembly II</p>
            <p>count The value of is:{props.count}</p>
        </div>
    );
};
const handleRender = ()=>{
    setRender(true)
}
return (
    <div style={{display:"flex",justifyContent:'center',alignItems:'center',height:'100vh',flexDirection:'column'}}>
        {/* {
            useMemo(() => {
                return <Childone />
            }, [render])
        } */}
        <Childone num={num}/>
        <Childtwo count={count} />
        <button onClick={handleAdd}>increase</button>
        <br/>
        <button onClick={handleRender} >Sub component I rendering</button>
    </div>
);

}

Copy code
This example is the result of removing the Childone in the previous example and inserting React.memo. After clicking Add, the component will not render repeatedly because num has not changed

useCallback
In the above example, we wrap handleRender with useCallback, that is to say, the num here does not change, and the same function will be transmitted every time. If the useCallback package is not used here, a new handleRender will be generated every time, resulting in a shallow comparison of props in the React.memo function. It is found that a new function is generated to trigger rendering

const Childone = React.memo((props) => {

console.log("The sub component is re rendered",props);
return <p>Sub assembly I{props.num}</p>;

})
export default function MemoDemo() {

let [count, setCount] = useState(0);
let [render,setRender] = useState(false)
let [num,setNum] = useState(2)
const handleAdd = () => {
    setCount(count + 1);
};

const Childtwo = (props) => {
    return (
        <div>
            <p>Sub assembly II</p>
            <p>count The value of is:{props.count}</p>
        </div>
    );
};
const handleRender = useCallback(()=>{
    setRender(true)
},[num])
return (
    <div style={{display:"flex",justifyContent:'center',alignItems:'center',height:'100vh',flexDirection:'column'}}>
        {/* {
            useMemo(() => {
                return <Childone />
            }, [render])
        } */}
        <Childone num={num} onClick={handleRender}/>
        <Childtwo count={count} />
        <button onClick={handleAdd}>increase</button>
        <br/>
        <button onClick={handleRender} >Sub component I rendering</button>
    </div>
);

}
Copy code
useRef
This hook is usually used to get component instances and can also be used to cache data ❗ There is no more explanation for obtaining instances. It should be noted that only class components have instances;
Focus on how useRef caches data:

function UseRef() {

let [data, setData] = useState(0)
let initData = {
    name: 'lisa',
    age: '20'
}
let refData = useRef(initData)   //After refData declaration, the component will render again and will not be assigned the initial value again
console.log(refData.current);
refData.current = {       //After modifying refData, the page will not be re rendered
    name: 'liyang ',
    age: '18'
}
const reRender = () => {
    setData(data + 1)
}
return (
    <div>
        <button onClick={reRender}>Click re render component</button>
    </div>
)

}
Copy code
After the component is re rendered, the variable will be re assigned. You can cache the data with useRef. After the data is changed, the component will not be triggered to re render. If you save the data with useState, the component will be re rendered after the data is changed. Therefore, we want to save the data quietly. useRef is the only choice 👊

Three custom hook s
Custom hook, that is, the encapsulation of hook. Why encapsulate hook? The answer is given on react's official website

One of the purposes of using Hook is to solve the problem that the life cycle function in class often contains irrelevant logic, but separates the relevant logic into several different methods. By customizing the Hook, component logic can be extracted into reusable functions.

Let's take a look at this example:

export default function CustomHook() {

let refone = useRef(null)
let X, Y, isMove = false,left,top
//Drag and drop based on mouse events
useEffect(() => {
    const dom = refone.current
    dom.onmousedown = function (e) {
        isMove = true
        X = e.clientX - dom.offsetLeft;
        Y = e.clientY - dom.offsetTop;
    }
    dom.onmousemove = function (e) {
        if (isMove) {
            left = e.clientX - X
            top = e.clientY - Y
            dom.style.top = top + "px"
            dom.style.left = left + "px"
        }

    }
    dom.onmouseup = function (e) {
        isMove = false
    }
}, [])
return (
    <div style={{ display: "flex", justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
        <div ref={refone} style={{ width: '70px', height: '70px', backgroundColor: '#2C6CF9',position:'absolute' }}></div>
    </div>
)

}
Copy code
We use mouse events to simply achieve a drag and drop grid effect. What if we need this effect on other pages? 😏 Therefore, we can consider encapsulating the same logic, just as we extract common components. Consider the following example:

import {useEffect, useRef } from "react";
function useDrop() {

let refone = useRef(null)
let X, Y, isMove = false,left,top
//Drag and drop based on mouse events
useEffect(() => {
    const dom = refone.current
    dom.onmousedown = function (e) {
        isMove = true
        X = e.clientX - dom.offsetLeft;
        Y = e.clientY - dom.offsetTop;
    }
    dom.onmousemove = function (e) {
        if (isMove) {
            left = e.clientX - X
            top = e.clientY - Y
            dom.style.top = top + "px"
            dom.style.left = left + "px"
        }

    }
    dom.onmouseup = function (e) {
        isMove = false
    }
}, [])
return refone

}
export default function CustomHook() {

let refone = useDrop()
let reftwo = useDrop()
return (
    <div style={{ display: "flex", justifyContent: 'center', alignItems: 'center', height: '100vh' }}>
        <div ref={refone} style={{ width: '70px', height: '70px', backgroundColor: '#2C6CF9',position:'absolute' }}></div>
        <div ref={reftwo} style={{ width: '70px', height: '70px', backgroundColor: 'red',position:'absolute' }}></div>
    </div>
)
}

Copy code
In order to reduce the amount of code, we only show the use of encapsulated hooks on the same page. In fact, we only changed a few lines of code to encapsulate this hook, but realized the reuse of logic. Isn't it amazing! 😆 It should be noted that the encapsulated function of hook must start with use, because the use of hook itself is regular. For example, hook cannot be used in conditional statements or outside functions; If it is not applicable to encapsulating hooks starting with use, react cannot automatically check whether the hooks used in the function comply with the rules.

last
If you think this article is a little helpful to you, give it a compliment. Or you can join my development exchange group: 1025263163 learn from each other, and we will have professional technical Q & A to solve doubts

If you think this article is useful to you, please click star: https://gitee.com/ZhongBangKe... esteem it a favor!

Keywords: hook

Added by Hallic7 on Fri, 12 Nov 2021 05:36:50 +0200