React依赖更新后Effect Hook未重新执行问题排查
问题根源
- 子组件问题:用
useState存储要暴露的方法对象导致ref更新延迟。初始渲染时useImperativeHandle返回null,只有等监听divEl.current的useEffect执行后,才会把真实方法对象赋值给ref,但此时父组件的初始useEffect已执行,拿到的是null。 - 父组件问题:将
oRef.current放入useEffect依赖数组无效,React不会追踪ref属性的变化,即便ref更新,useEffect也不会自动重新执行。
修复后的代码
Child.tsx
import { forwardRef, useImperativeHandle, useState } from 'react' const Child = forwardRef<{ setValue: (v: string) => void }, {}>((_, ref) => { const [val, setVal] = useState('') useImperativeHandle( ref, () => ({ setValue(v: string) { console.log('value', v) setVal(v) } }), [setVal] ) return <div>{val}</div> }) export default Child
Parent.tsx
import React, { useEffect, useRef, useState } from 'react' import Child from './Child' const Parent: React.FC = () => { const oRef = useRef<{ setValue: (v: string) => void }>(null) const [count, setCount] = useState(0) useEffect(() => { console.log('useEffect setValue') oRef.current?.setValue(String(Date.now())) }, []) return ( <div> <div> <Child ref={oRef} /> </div> <div> <button onClick={() => { setCount(c => c + 1) oRef.current?.setValue(String(Date.now())) }}>Click Me</button> <div>{count}</div> </div> </div> ) } export default Parent
修复说明
- 子组件优化:
- 移除多余的
obj状态和监听divEl.current的useEffect,直接在useImperativeHandle中返回包含setValue的对象,该方法直接调用setVal更新状态。 - 子组件首次渲染时就会把可用的方法对象赋值给ref,不再出现
null的情况。 - 给ref添加TypeScript类型,避免使用
any,提升代码安全性。
- 移除多余的
- 父组件优化:
- 将
useEffect依赖数组改为空数组,确保组件挂载后仅执行一次,此时子组件的ref已准备就绪。 - 点击按钮时直接调用
setValue,无需依赖useEffect,逻辑更清晰。
- 将
内容的提问来源于stack exchange,提问作者pansong291
相关产品推荐
相关产品推荐

