能否在传入useCallback的函数内部调用setState?
结论
官方文档的限制仅针对直接作为useMemo入参的内联函数内部,与你缓存的fn本身无关,自然也不限制useCallback包裹的函数内部写副作用。
具体解释
- 首先明确两者的执行时机差异
你写的代码const res = useMemo(() => fn, []);里,有两个完全独立的函数:
- 传给
useMemo的匿名函数() => fn:会在组件渲染过程中同步执行,React需要拿到它的返回值来生成缓存的res。渲染过程中不能执行副作用(比如setState)是因为会触发重复渲染,甚至死循环,这就是官方文档限制的范围。 - 被缓存的
fn:在渲染阶段完全不会被执行,只是被当做一个普通值存在res里而已。它的执行时机完全由你控制,只要你不在渲染过程中直接调用它,内部写任何逻辑都符合规范。
- 关于
useCallback的误解澄清useCallback(fn, deps)等价于useMemo(() => fn, deps)的本质,是说两者都是用来缓存fn这个函数值,不会在渲染阶段执行fn本身。
我们日常把useCallback返回的函数作为点击事件回调、useEffect依赖、异步任务回调使用时,执行时机都不在渲染过程中,所以完全可以在里面写setState、接口请求这类副作用,这也是React的常规用法。
反例参考
只有你在渲染过程中直接调用useCallback返回的函数时,才会触发问题,这种写法本身就是错误的:
const addCount = useCallback(() => { setCount(prev => prev + 1) }, []) // 错误写法:渲染期间直接调用,会触发死循环 addCount() return <button onClick={addCount}>正常调用,没有问题</button>
内容的提问来源于stack exchange,提问作者gmoniava
相关产品推荐
相关产品推荐

