父组件通过 Props 向子组件传递函数实现单向通信:父定义函数(useCallback 避免重渲染)、子接收并调用,支持传参通知具体操作,需注意 this 绑定、引用稳定和类型校验。

在 React 中,父组件通过 Props 向子组件传递函数,是最基础也最常用的父子通信方式。核心就一点:把函数当作普通值传下去,子组件接收后调用它,就能触发父组件里的逻辑。
为什么传函数?而不是直接改状态
React 的数据流是单向的(自上而下),子组件不能直接修改父组件的状态。想让子组件“通知”父组件做某事(比如点击后关闭弹窗、提交表单、切换选项),就必须由父组件提供一个函数,子组件调用它来间接驱动变化。
- 保持状态管理集中——所有状态仍由父组件控制
- 避免子组件副作用失控——不自己 setState,只负责“喊一声”
- 函数名要有语义——比如 onConfirm、onChangeTab,比 handleClick 更易维护
怎么传?三步写清楚
以“点击按钮更新父组件计数”为例:
- 父组件定义函数并绑定 this(函数组件用 useCallback):避免每次渲染都生成新函数,防止子组件不必要的重渲染
-
作为 prop 传给子组件:例如
<ChildButton onClick={handleIncrement} /> -
子组件接收并调用:在事件处理器里执行
this.props.onClick()(类组件)或props.onClick()(函数组件)
传参技巧:让父函数知道“谁点的、点了啥”
子组件调用时可以传参数,父组件函数用形参接收:
- 子组件中:
onClick={() => props.onDelete(item.id)} - 父组件中:
const onDelete = (id) => { setList(list.filter(i => i.id !== id)); } - 注意别直接写
onClick={props.onDelete(item.id)}——这会立即执行,不是点击时执行
常见坑和应对
-
函数内 this 指向丢失(类组件):用箭头函数定义,或在 constructor 里 bind,或用 class fields 语法(
handleClick = () => {}) - 子组件重复渲染:没用 useCallback 包裹函数,导致每次父组件更新都传入新函数引用
-
类型校验缺失(TS):给 Props 接口明确声明函数签名,比如
onSubmit: (data: FormValues) => void

















