请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

关于useCallback和useMemo第二个参数的问题

老师请问useCallback可以像useMemo的第二个参数写条件表达式吗图片描述
试了一下为什么只有第一次有效果加一了,
还有个疑问就是useCallback如果不可以写条件判断的话,只能写依赖的状态,第一次渲染的时候这个函数可以执行,当clickCount改变的时候这个函数可可以执行,这么理解对吗?感觉有点绕,那useMemo第二个参数满足条件的时候才可以执行,那为什么从第一次不满足条件的时候还可以执行呢

正在回答

2回答

你好同学,useMemo/useCallback/useEffect第二个参数是一致的,都可以传入任意复杂度的同步计算表达式。

根据你的描述,我推测出下面的代码:

function App() {
  const [clickCount, setClickCount] = useState(0);  

  const handleClick = useCallback(() => {
    setClickCount(clickCount + 1);
  }, [clickCount === 2]);

  return (
    <div>
        <button onClick={handleClick}>Press</button>
        <span>{clickCount}</span>
    </div>
  )
}

export default App;

多次点击按钮,显示的clickCount一直是1,这是正确的。

这是因为,clickCount === 2这个表达式的值没变,造成了handleClick没变,同时里面引用的上下文也没变,clickCount一直停留在0的状态,即使加1,最多也就变成1,并不会再变了。

具体是这样的过程:

  1. 首次渲染,handleClick所指向的这个函数,它读取到的上下文是 {clickCount: 0};

  2. 点击按钮,调用 setClickCount,clickCount变成1,触发第二次渲染;

  3. 第二次渲染,计算useCallback的第二个参数,发现依然是false,那么useCallback依然会返回之前的函数给 handleClick,handleClick内部能读取到的 clickCount 依然是0;

  4. 再次点击按钮,调用handleClick,setClickCount还是只能传入 0+1,还是1,React发现数据相同,不会触发重新渲染;

  5. 一直保持这个状态

之所以出现这个问题是你实际上引入了一个闭包,也就是handleClick引用了外部上下文的数据,而作为函数组件,每次重新渲染,都会创建一个新的上下文,而handleClick句柄指向的还是旧上下文。

解决这个问题很简单,就是传入函数给 setClickCount:

setClickCount(count => count + 1)

这样并没有引用任何上下文的数据,因此是安全的。当然把useCallback的第二个参数改成 [clickCount] 或者不加第二个参数也能解决问题。

作为第二个依赖参数,没有满足与不满足的说法,只有变化与未变化,只有变化了才会重新执行,第一次渲染的时候,无从对比,都会先执行一次,不论useMemo/useCallback还是useEffect。


祝您学习愉快!

2 回复 有任何疑惑可以回复我~
提问者 qq_我的心向大海_ckuGNU 2019-05-22 18:07:29

这个老师不用回答啦,上个问题已经帮我解决了,感谢老师

0 回复 有任何疑惑可以回复我~
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信