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

React严格模式下react-transition-group报findDOMNode废弃,加nodeRef后UI异常

问题原因

你在组件顶层仅声明了一个共用的nodeRef引用,当通过map循环渲染多个待办项时,这个唯一的ref会在循环过程中被不断覆盖,最终只会指向最后一个渲染的<li>元素。所有<CSSTransition>组件拿到的nodeRef都指向同一个元素,导致前面的列表项找不到对应的DOM节点,无法正常渲染和触发动画,因此出现部分元素丢失的异常。

正确修复方案

推荐将循环渲染的单个待办项抽离为独立的子组件,每个子组件内部单独维护自己的nodeRef,保证每个<CSSTransition>和对应的DOM节点一一绑定,不会出现引用冲突。

步骤1:抽离独立的TodoItem子组件

const TodoItem = ({ task, toggleTodo, styles }) => {
  // 每个子组件内部维护独立的ref
  const nodeRef = React.useRef(null);
  
  return (
    <CSSTransition
      timeout={500}
      classNames={styles}
      nodeRef={nodeRef}
    >
      <li ref={nodeRef}>
        <TodoTask
          todo={task}
          onClick={(todo) => toggleTodo({ data: todo })}
        />
      </li>
    </CSSTransition>
  )
}

步骤2:父组件中引用子组件

<ul>
  <TransitionGroup className="todo-list">
    {incompleteTodos.map((task) => (
      <TodoItem 
        key={task.id} 
        task={task} 
        toggleTodo={toggleTodo} 
        styles={styles} 
      />
    ))}
  </TransitionGroup>
</ul>

可选方案:使用ref数组(不推荐)

如果不想抽离子组件,也可以创建ref数组存储每个列表项的独立引用,但是该方案需要手动维护ref数组和列表项的对应关系,适合列表项固定、无频繁增删排序的场景:

// 父组件内声明ref数组
const nodeRefs = React.useRef([]);

// 渲染时分配独立ref
<ul>
  <TransitionGroup className="todo-list">
    {incompleteTodos.map((task, index) => {
      if (!nodeRefs.current[index]) {
        nodeRefs.current[index] = React.createRef();
      }
      return (
        <CSSTransition
          key={task.id}
          timeout={500}
          classNames={styles}
          nodeRef={nodeRefs.current[index]}
        >
          <li ref={nodeRefs.current[index]}>
            <TodoTask
              todo={task}
              onClick={(todo) => toggleTodo({ data: todo })}
            />
          </li>
        </CSSTransition>
      )
    })}
  </TransitionGroup>
</ul>

内容的提问来源于stack exchange,提问作者Varun Sukheja

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.09 03:36:03