子组件不能直接修改父组件状态,必须通过父组件传递的更新函数(如onItemDelete)触发父组件state变更并重新传入。状态应提升至最近共同祖先,子组件仅调用setter、不维护副本,避免深拷贝或useEffect反向写回;深层嵌套时可考虑Context或状态库。

子组件不能直接改父组件的状态,这是 React 单向数据流的铁律。所谓“同步”,其实是子组件触发父组件更新,再由父组件把新状态重新传下来——整个过程靠函数传递和状态提升来实现。
把状态提到父组件统一管理
这是最根本的一步。不要在子组件里用 useState 复制父组件传来的 props 数据,否则就断开了同步链路。比如父组件传了个 items 列表,子组件想删其中一项,就得让父组件自己删,而不是在子组件里删自己的副本。
- 选中最近共同祖先组件(通常是父组件本身)声明
const [items, setItems] = useState([...]) - 把
items和setItems都作为 props 传给子组件 - 子组件只负责调用
setItems,不维护独立状态
用回调函数暴露更新能力
父组件传下来的不是数据本身,而是“怎么改数据”的能力。这个函数就是子组件操作父状态的唯一入口。
- 命名建议清晰,比如
onItemDelete、onCategoryChange,而不是笼统的onChange - 函数体内直接调用父组件的 setter,或封装一层逻辑后再调用
- 确保子组件调用时参数结构与父组件预期一致,避免
props.onItemDelete is not a function报错
子组件内避免副作用式修改
有些同学会在子组件里对 props 做深拷贝、再 mutate,或者用 useEffect 监听 props 变化后反向写回——这些都绕过了 React 的响应机制,容易引发竞态或视图滞后。
- 所有状态变更必须走父组件的 setter 函数
- 如果子组件需要中间计算(如过滤、排序),可用派生状态:用
useMemo基于传入的items计算,但不存为可变 state - 模态框、表单等复杂交互,可配合
useReducer或自定义 Hook 封装更新逻辑,再透传 dispatch
深层嵌套时考虑 Context 或状态库
当 props 要跨 3 层以上组件传递,手动透传会变得脆弱且难维护。这时可以引入更稳定的通信层:
-
React.createContext适合局部共享(如主题、用户信息),避免 prop drilling - 全局状态较重时(如多步表单、实时协作),再评估 Redux、Zustand 等方案
- 注意 Context 不是万能替代:频繁更新的值可能引发不必要的重渲染,需搭配
useMemo或useReducer优化

















