03 React Hook的应用
1 Hook是什么?为什么要用它?
hook本质是个有点不一样的函数,不一样在于返回的值,如常用的useState,用于保存状态,那么它是怎么保存其状态的。我们知道一个组件函数被调用(渲染)
里面的引用函数就一定也会被调用了,之所以useState能保存状态是因为它能返回跟上次组件函数一样的结果,所以它是稳定的,也就是能保存组件的了状态.
这样一来,函数组件不就跟类组件一样有状态了吗。而这只是hook中的一个.   
  好,回到标题的问题:Hook是什么?Hook本质是个函数,但会根据函数组件的情况,不同的hook有不同的实现功能。   
  那为什么要用它?相较类组件,函数组件简单轻量,好拆分,但函数组件就是函数,没有类组件的对应的状态和生命周期功能,而这些功能或多或少可能通过
Hook来弥补实现出来,这就是Hook的意义。
2 useCallback的使用
userCallback 和 userCallback的作用是什么? React有一个过滤调用(渲染)的情况,组件的更新本质上就是把该函数重新调用一遍,但往后的子组件,
可能不需要调用了,就是没必要了。而组件的调用(渲染)触发条件是state或props发生变动才重新调用(渲染)自身。说白了,一但组件内有一丁点的关于props
或state或其它hook的变化都会引发组件全部重新再运行一次,也直接波及到全部子组件的更新。这是是函数组件更新的方式,避免不了,但可以避免一些代码块
就重复调用和子组件被动调用的渲染的情况。而组件内的代码块避免再次被调用则可以用userCallback来实现
2.1 useCallback示例
useCallback的接收2个参数,一个是不变的回调函数,一个是依赖的state,依赖变了,函数才会重新刷新一个新的版本,如果没有则,默认不变。
import React, {useCallback, useState} from "react";
const UseCallbackDemo = (): React.ReactElement => {
    const [count, setCount] = useState<number>(0)
    const callback = useCallback(() => {
        console.log("callback的内部访问到的count值: " + count)
        // todo some thing ...
    }, [])
    return (
        <>
            <p>count: {count}</p>
            <button onClick={() => setCount(() => count + 1) }>修改count</button>
            <button onClick={callback}>在useCallback内部打印count</button>
        </>
    )
}
export default UseCallbackDemo
后面不管理怎么修改count,而对于callback来说,count就是0,因为callback是不变的,哪怕由于外面的count引发组件多次刷新,可由于callback
并没有更新,而callback内部一开始访问到的count也就是组件第一次初始化时的参数就是0. 所以它就只能在控制台中打印出"callback的内部访问到的count值: 0"这样
的结果。
而这样一来,我们是得到了一个不会随着组件渲染而产生的新的版本的函数了,但有时userCallback中还是需要使用最新的state的,最直接的方式有:
- 1 把需要用到的最新
state的加入userCallback的依赖数组中。 - 2 也可以使用
useReducer的方式,通过dispatcher的方式,把对state的处理委托给useReducer来处理, 这样的好处是相对于依赖的每次都要更新一次, 不可以直观地在代码中决定要不要处理关于state的问题,另一个好处就是普通的防抖算法是基于时间的来采样的,这样把逻辑写userCallback可以避免产生新的 版本,从而保证防抖算法的稳定,而需要处理最新的state时,则直接委托给useReducer来处理就可以了。 
3 React.memo 函数的使用
这个函数的作用于子组件和父组件之间,如果父组件更新了,子组件也会被动更新,不管有没有props的变动。而React.memo的作用包裹子组件用的,充当一个中间者的作用,
就是当父组件更新时,如果没有props的更新,那么React.memo就是不会让子组件渲染
import React, {useState} from "react";
const Children1 = () => {
    console.log('Children1 reload.')
    return <>Children1</>
}
const Children2 = React.memo(() => {
    console.log('Children2 reload.')
    return <>Children1</>
})
const UseMemoDemo = (): React.ReactElement => {
    const [count, setCount] = useState<number>(0)
    console.log("Parent component reload." + count)
    return (<>
        <Children1 />
        <br />
        <Children2 />
        <br/>
        <button onClick={() => setCount(() => count + 1)}>Reload component</button>
    </>)
}
export default UseMemoDemo;
以上示例,在打印台中可以看出,如果父组件更新了,子组件也会被动更新,而使用了React.memo函数则避免了这种过多的渲染。
4 useMemo的使用
useMemo跟useCallback的用法一样,而跟后者返回一个函数不一样的是useMemo返回的是一个固定的变量。它的作用是,如果子组件接收的属性是复合类型,也就是
一个自定义的对象时,尽管数值没变,但还是会引发子组件的更新,我猜这是因为在js中,自定义的复合类型尽管每次都值是一样的,但底层的内存地址已经不一样了,从而
子组件把该属性判定为新的组件而触发子组件的更新。而useMemo则能保证被自定义的值是不一变的。
import React, {useMemo, useState} from "react";
 type InfoType = {text: string}
 type ChildrenPropsType = {info: InfoType}
 const Children1 = () => {
     console.log('Children1 reload.')
     return <>Children1</>
 }
 const Children2 = React.memo(({info}: ChildrenPropsType) => {
     console.log('Children2 reload.' + JSON.stringify(info))
     return <>Children2</>
 })
 const Children3 = React.memo(({info}: ChildrenPropsType) => {
     console.log('Children3 reload.' + JSON.stringify(info))
     return <>Children3</>
 })
 const UseMemoDemo = (): React.ReactElement => {
     const [count, setCount] = useState<number>(0)
     console.log("Parent component reload." + count)
     const text2: InfoType = {text: 'text2'}
     const text3 = useMemo((): InfoType => ({text: "text3"}), [])
     return (<>
         <Children1 />
         <br />
         <Children2 info={text2} />
         <br/>
         <Children3 info={text3} />
         <button onClick={() => setCount(() => count + 1)}>Reload component</button>
     </>)
 }
export default UseMemoDemo;
以上示例中会打印:
Parent component reload.2
index.tsx:5 Children1 reload.
index.tsx:9 Children2 reload.{"text":"text2"}
参考资料
useCallback()、useMemo() 解决了什么问题? React useCallback的实际应用 为什么要用这个函数?