You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React依赖更新后Effect Hook未重新执行问题排查

问题根源

  1. 子组件问题:用useState存储要暴露的方法对象导致ref更新延迟。初始渲染时useImperativeHandle返回null,只有等监听divEl.current的useEffect执行后,才会把真实方法对象赋值给ref,但此时父组件的初始useEffect已执行,拿到的是null。
  2. 父组件问题:将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 16:49:56