React 常用hooks

66 阅读3分钟
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script>
        /*
        1. RN hooks 用法:
        (1) const [num, setNum] = useState(()=>{
            const num1 = 1 + 2
            const num2 = 2 + 3
            return num1 + num2
        })
        (2) 独立值: const [num, setNum] = useState(2)

        2.setNum 函数用法: setNum((pre)=>pre + 1)

        3.useEffect 副作用函数(可以额外处理一些功能) 不支持async await,可以放计时器或者请求数据 等异步逻辑
        (1) useEffect(()=>{
            getApiData() // 请求接口数据
        }, []) // 依赖变化的值,一般是状态值
        (2) useEffect 中清理计时器
        useEffect(()=>{
            const timer = setInterval(()=>{

            }, 1000)
            return () =>{
                clearInterval(timer) // 清理计时器
            }
        })

        (3) useLayoutEffect: 等effect 函数中内容执行完后再渲染, 好处页面会不闪动,坏处时间过长有可能阻塞页面渲染

        (4) useReducer 场景: 在修改状态值之前要执行一些固定逻辑
        import { Reducer, useReducer} from 'react'

        // 固定逻辑函数
        const reducer = (state, action) =>{
        switch(action.type) {
            case 'add':
                return {
                    result: state.result + action.num  // 只有类似返回新对象才能触发重新渲染(state.result +=action.num   return state 无法重新渲染)
                }
            case 'minus': 
                return {
                    result: state.result - action.num
                }
            }
            return state;
        }
        const [res, dispatch] = useReducer(reducer, { result:0})  // (1.函数, 初始值)
        注意触发函数: dispatch({ type: 'minus', num: 1 })  结果值 res.result

        (4) 总是返回新对象,性能不好,复杂对象就要用到immer库了 npm install --save immer
        return produce(state, (state)=>{state.a.c.e + = action.num})  // 将state 中的a对象中的 c对象中的 e 属性加上 action 中num的值
        immer 是依赖 Proxy 实现的,它会监听你在函数里对属性的修改,然后帮你创建一个新对象
        
        useState 中 onClick={() => {
                obj.a.c.e ++;
                setObj(obj);   // 这样也不会触发重新渲染, 因为对象引用未变
            }}
        总结: react 中 只要涉及到state状态值的修改,必须返回新的对象, 不管是useState 还是useReducer
        如果是复杂深层对象的修改,可以用immer 来优化, 为啥react推崇的数据不可变呢就是这个原因

        4. useRef 场景: 里面有current属性引用, 用来保存dom的引用或者别的内容,但是它不会触发重新渲染
        想要重新渲染, 可以配合useState(0) 进行重新设置一个任意值

        5.单个组件拿到ref 直接使用useRef, 那么想把ref从子组件传递到父组件呢?  forwardRef + useImperativeHandle
        
        const children =forwardRef((props, ref)=>{
            // 暴露给父组件的方法
            useImperativeHandle(ref, ()=>{
                return {
                    aaa(){
                        inputRef.current?.focus()
                    }
                }
            }, [inputRef])

            const inputRef = useRef(null)

            return (
                <input ref={inputRef}>

                </input>
            )
        })
        const components = ((props)=>{
            const childrenRef = useRef(null)
            useEffect(()=>{
                // 父组件中调用子组件的方法
                childrenRef?.current?.aaa()
            })
            return <div>
                {{
                    <children ref={}>
                }}
                </div>
        })


        6.useContext: 跨任意层级组件传递数据, 一般用context, 配置数据基本都用context传递
        组件A -----> context ---> 组件B
        import { createContext, useContext } from 'react'
        const countContext =createContext(111)  // 创建
        const AAA = ()=>{
            return (
                <countContext.Provider value = {222}>  // 修改值
                    <BBB></BBB>
                </countContext.Provider>
            )

        }
        const BBB = () =>{
            return (
                <div>
                    <CCC></CCC>
                </div>
            )
        }
        const CCC = ()=>{
            const count = useContext(countContext)  //useContext 取出来使用
            return <div>{count}</div>
        }

        7.memo + useMemo + useCallback
        (1)
        const AAA = () =>{
            count [, setNum] = useState(1)
            useEffect (()=>{
                setInerval(()=>{
                    setNum(Math.random())
                })
            }, [])
            return(
                <BBB count ={2}>
                </BBB>
            )
        }

        const BBB = (props)=>{
            console.log('会执行几次?')
            return <h2>{
                props?.count
            }</h2>
        }

        注意: 每两秒都会打印一次, 也就是每次都会触发BBB 组件的重新渲染, 很明显组件B 并不需要重新渲染, 这时候可以加上memo
        import {memo} from react
        const MemoBBB = memo(BBB)
        const AAA = ()=>{
            return(<MemoBBB count ={2}></MemoBBB>)
        }

        总结: memo的作用是只有props变的时候,才会重新渲染包裹的组件

        (2) memo 是防止props没变化时的重新渲染, useMemo 和 useCallback 是防止 props的不必要变化
        const BBBcallback = ()=>{

        }
        <MemeBBB count={count} callback = {BBBcallback}></MemoBBB> 你会发现memo失效了,因为函数每次都是新创建的, 这样就是需要useCallback了
        
         const BBBcallback = useCallback(()=>{

         }, [])  // 当deps数组没有变化时候, 都返回同一个函数, 只有当deps数组变化时候, 才把函数设置为新传的函数, 相当于函数缓存

         同样useMemo 也是和memo打配合, 只不过它保存的不是函数, 而是值

         const count2 = useMemo(()=>{
            return count * 10
         }, [count])
         const bbbCallback = useCallback(()=>{
            console.log('进行函数缓存!')
         }, [])

         <MemoBBB count={count2} callback={bbbCallback}></MemoBBB>

         总结: memo 使用总是需要 useMemo & useCallback 来帮忙, 但是 useMemo & useCallback 不仅仅帮助memo
         




        
        

















        */
       
    </script>
</body>
</html>