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);
问题原因
- 组件定义位置错误:
Test组件定义在App内部,每次App因状态更新重渲染时,都会重新创建一个全新的Test组件。这导致之前添加到component数组里的Test是旧的组件引用,内部的setComponent捕获的是创建该组件时的旧component状态值,无法正确更新最新状态。 - 闭包陷阱:
Add2按钮的点击事件依赖闭包中的component值,但这个值是创建当前Test组件时的快照,不是最新的状态,所以点击后无法正确添加新组件。 - 无用的
useEffect:代码中的useEffect没有依赖项也没有执行逻辑,属于冗余代码。 - 使用
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重渲染都重新创建组件,保证组件引用稳定。 - 通过
onAddprops把状态更新方法传给Test,避开闭包陷阱,确保点击时调用的是最新的状态更新逻辑。 - 使用函数式更新
setComponentList,每次更新都基于最新的前一次状态,避免依赖闭包中的旧值。 - 用自增
id作为组件key,避免索引key带来的渲染问题。
内容的提问来源于stack exchange,提问作者user19639519
相关产品推荐
相关产品推荐

