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

React中Test组件内Add2按钮失效,请求排查问题原因

React组件内按钮点击无响应问题排查

我有两个按钮:Add1和Add2。Test组件内的Add2按钮无法正常工作。我对React不太熟悉,请问我哪里出错了?

原代码

import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react-lite";

function App() {
  const [component, setComponent] = useState([]);

  useEffect(() => {});

  const Test = observer(() => {
    return (
      <div>
        <p>
          Test -
          <button onClick={() => setComponent([...component, Test])}>
            Add 2
          </button>
        </p>
      </div>
    );
  });

  return (
    <div>
      {component.map((Input, index) => (
        <Input key={index} />
      ))}
      <button onClick={() => setComponent([...component, Test])}>Add 1</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

问题原因

  1. 组件定义位置错误:Test组件定义在App内部,每次App因状态更新重渲染时,都会重新创建一个全新的Test组件。这导致之前添加到component数组里的Test是旧的组件引用,内部的setComponent捕获的是创建该组件时的旧component状态值,无法正确更新最新状态。
  2. 闭包陷阱:Add2按钮的点击事件依赖闭包中的component值,但这个值是创建当前Test组件时的快照,不是最新的状态,所以点击后无法正确添加新组件。
  3. 无用的useEffect:代码中的useEffect没有依赖项也没有执行逻辑,属于冗余代码。
  4. 使用index作为key的隐患:虽然不是按钮失效的直接原因,但用数组索引作为组件key,在组件顺序变化时会导致React渲染异常,应该使用唯一标识。

修复方案

把Test组件移到App外部,通过props传递状态更新方法,同时使用函数式更新确保获取最新状态:

import React, { useState } from "react";
import ReactDOM from "react-dom";
import { observer } from "mobx-react-lite";

// 将Test组件移到App外部,保证组件引用稳定
const Test = observer(({ onAdd }) => {
  return (
    <div>
      <p>
        Test -
        <button onClick={onAdd}>Add 2</button>
      </p>
    </div>
  );
});

function App() {
  const [componentList, setComponentList] = useState([]);
  // 用自增id生成唯一key,替代index
  const [nextId, setNextId] = useState(1);

  const addNewComponent = () => {
    // 函数式更新,基于最新状态修改
    setComponentList(prevList => [...prevList, { id: nextId, Component: Test }]);
    setNextId(prevId => prevId + 1);
  };

  return (
    <div>
      {componentList.map((item) => (
        <item.Component key={item.id} onAdd={addNewComponent} />
      ))}
      <button onClick={addNewComponent}>Add 1</button>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

修复说明

  • 将Test移到App外部,避免每次App重渲染都重新创建组件,保证组件引用稳定。
  • 通过onAdd props把状态更新方法传给Test,避开闭包陷阱,确保点击时调用的是最新的状态更新逻辑。
  • 使用函数式更新setComponentList,每次更新都基于最新的前一次状态,避免依赖闭包中的旧值。
  • 用自增id作为组件key,避免索引key带来的渲染问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 10:24:14