如何在 React 中正确地在兄弟组件间传递状态数据

2次阅读

如何在 React 中正确地在兄弟组件间传递状态数据

本文详解 react 应用中 toolbarelement 与 graphelement 两个兄弟组件间共享状态的正确实现方式,涵盖状态提升、可变性陷阱规避、异步数据流处理及 props 传递规范,避免因直接修改 props 导致的运行时错误。

react 中,子组件之间无法直接通信——它们必须通过共同的父组件(如 App.js)进行状态协调。你当前代码中的核心问题并非“传参语法”,而是对 React 状态机制的根本性误解:props 是只读的,不可被子组件直接修改。因此,ToolbarElement.js 中 state.graph_data = data.lst[0] 这一行会报错 Cannot set properties of undefined(因为 props.state 实际上是普通对象字面量,且 state 并未作为可变引用透传),同时 GraphElement 也无法响应式更新。

✅ 正确做法:状态提升(Lifting State Up)

将共享状态及其更新逻辑统一托管到父组件 App.js 中,再通过 props 单向向下传递状态值和更新函数

1. 修改 App.js:使用 useState 管理可变状态

import React, { useState } from 'react';  function App() {   // ✅ 使用 useState 创建响应式状态   const [graphData, setGraphData] = useState(0);    return (     <div className="App">       <div className="App-body">         <div className="toolbar-element" style={{ top: "50px", left: "0px" }}>           {/* ✅ 向 ToolbarElement 传递状态值 + 更新函数 */}           <ToolbarElement graphData={graphData} setGraphData={setGraphData} />         </div>         <div className="graph-element" style={{ top: "50px", right: "0px" }}>           {/* ✅ 向 GraphElement 仅传递状态值(只读) */}           <GraphElement graphData={graphData} />         </div>       </div>     </div>   ); }  export default App;

2. 修改 ToolbarElement.js:触发异步请求并更新父状态

import React, { useState } from 'react';  function ToolbarElement({ graphData, setGraphData }) {   const [loading, setLoading] = useState(false);    const handleButtonClick = async () => {     setLoading(true);     try {       const res = await fetch("/data");       if (!res.ok) throw new Error(`HTTP ${res.status}`);       const data = await res.json();        // ✅ 安全校验:确保 data 是数组且非空       if (Array.isArray(data) && data.length > 0) {         setGraphData(data[0]); // ? 触发父组件状态更新,GraphElement 自动重渲染       } else {         console.warn("API returned empty or invalid data");         setGraphData(NULL);       }     } catch (err) {       console.error("Failed to fetch graph data:", err);       setGraphData(null);     } finally {       setLoading(false);     }   };    return (     <div style={{ height: '33.33%', backgroundColor: '#F0F0F0' }}>       <button onClick={handleButtonClick} disabled={loading}>         {loading ? 'Loading...' : 'Click me!'}       </button>     </div>   ); }  export default ToolbarElement;

3. 修改 GraphElement.js:安全渲染状态

function GraphElement({ graphData }) {   // ✅ 增强健壮性:处理 null/undefined 或非字符串类型   const displayValue = graphData == null ? 'No data' : String(graphData);    return (     <div style={{ height: '33.33%', backgroundColor: '#E8E8E8' }}>       <p>{displayValue}</p>     </div>   ); }  export default GraphElement;

⚠️ 关键注意事项

  • 永远不要修改 props:React 的 props 是不可变的契约,直接赋值(如 props.state.x = y)不仅无效,还会破坏组件一致性。
  • 避免在子组件中定义状态对象字面量:原 App.js 中 const state = { graph_data: 0 } 是静态对象,不具响应性;必须用 useState 或 useReducer。
  • 异步操作需错误处理:网络请求可能失败,务必包裹 try/catch 并提供 fallback 状态。
  • 类型安全建议:若项目使用 typescript,可为 graphData 添加明确类型(如 number | string | null),进一步规避运行时错误。
  • 性能优化(进阶):当 GraphElement 较复杂时,可用 React.memo 包裹防止不必要的重渲染。

通过以上重构,GraphElement 将能实时响应 ToolbarElement 的按钮点击,并安全展示从 flask /data 接口获取的首项数据——整个流程符合 React 单向数据流原则,稳定、可维护、易调试。

text=ZqhQzanResources