React-Hooks闭坑指南

100 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第16天,点击查看活动详情 

复杂逻辑useState中传函数

useState可以传递函数,作为默认参数

// 这个函数只在初始渲染时执行一次,后续更新状态重新渲染组件时,该函数就不会再被调用
function getInitState(){
return {number:props.number};
}
let [counter,setCounter] = useState(getInitState);

注意setState是异步的。在下次更新页面的时候才能获取最新的值

防止子组件props没变化的更新

子组件除了用React.memo包裹组件外。传递给子组件的对于高开销的值用useMemo 方法要用useCallback 。低开销不要用,因为缓存函数本身也耗费性能

const Parent = () => {
const [visible, setVisible] = useState(false);
const [visible2, setVisible2] = useState(false);
return (
   <>
       <Child1 visible={visible} />
       <Child2 visible={visible2} />
    </>
)
}

export default React.memo(() => {
    return <child1></child1>
})

hook定义顺序一定要保持不变,不能用条件判断来定义hook

if(value) {
    const [state, setState] = useState(0)
}
if(value2) {
    useEffect(() => {},[])
}

useEffect中调用函数,要在useEffect里面声明并调用

保证useEffect依赖的变量一目了然。 也就是逻辑写在useEffect,如果调用函数,函数定义也需要定义在useEffect中。 如果函数写在外面一定要保证是否有依赖,即第二个参数deps

setState的时候用到了原来的state一定要用函数

因为极有可能造成闭包陷阱

    const [state, setState] = useState(0)
    setState(state + 1) // 容易闭包陷阱
    setState(state => state + 1) // 容易闭包陷阱

useEffect里面改变state的值一定要,因为state变化的所以deps一定要配置依赖的state,否则也会导致闭包陷阱

我们要做的是页面首次进入弹框显示10秒后

useEffect(() => {
    const countdownHandler = () => {
        if (countdown === 10) return
        setTimeout(() => {
            setCountdown(countdown + 1)
            countdownHandler()
        }, 1000)
    }
    if (tabVisible) {
        countdownHandler()
    }
}, [tabVisible])

上面问题都存在。闭包导致countdown永远都是0 更改方式

useEffect(() => {
    const countdownHandler = () => {
        if (countdown === 10) {
            setTabVisible(false)
        }
        setTimeout(() => {
            setCountdown(countdown=>countdown + 1)
        }, 1000)
    }
    if (tabVisible) {
        countdownHandler()
    }
}, [tabVisible, countdown])

或者使用useRef缓存值。解决闭包问题

const count = useRef(0)

const countdownHandler = () => {
    if (count.current === 10) return
    setTimeout(() => {
        count.current += 1
        countdownHandler()
    }, 1000)
}

useState如果是对象或者数组的时候要解构赋值

实际上如果是对象就是相当于多个useState合并的操作

如下面例子会报错

const [count, setCount] = useState([1, 2]);
setCount(count => count.push(6)) 

应该改为

setCount([ ...count, 6 ])