本节摘要:组件间最常见的通信场景有三类——父传子的 props 下行、子报父的事件上行、兄弟或跨层共享。本节给出一张"遇到什么场景该用哪种通信"的全景表,并分别说明 React 与 Vue 的写法,避免新手一律硬塞 props。
本节阅读目标
阅读完本节,你应当能够:
每种形态对应一套工具,强用同一招反而绕路。先记住这个直觉:数据该放在"能通过 props 覆盖所有使用者的那层"。
React 用 props + 回调:
function Child({ value, onChange }) { return <button onClick={() => onChange(value + 1)}>加一</button>; } function Parent() { const [n, setN] = useState(0); return <Child value={n} onChange={(v) => setN(v)} />; }
Vue 用 props 下行、emit 上行:
<script setup> const props = defineProps({ value: Number }); const emit = defineEmits(['change']); function add() { emit('change', props.value + 1); } </script> <template> <button @click="add">加一</button> </template>
Vue 里父组件用 @change="n = $event" 接收。两者是同一套"数据下行、事件上行"心法在语法上的镜像。
兄弟组件要共看一份数据时,React 用状态提升(3.4 节),Vue 同样把数据提到公共父级再下发。当跨好几层、"中间层仅仅透传"时,硬 props 会变得冗长,这时可选:
判断标准:只是一两层就状态提升够用;链太长、太散才升级手段。

给组件通信开评审会时,按这个顺序提问:能只靠 props 往下推进吗?事件能不能在上层收敛?兄弟共享要不要提升?链深不透传还是用另外的注入?一路问下来,方案自然清晰,很少需要动用重型状态库。
拿"购物车角标"这个典型需求走一遍,就能把这些手段串起来。页面里有个商品详情、一个购物车图标,两处都要显示当前购物车中件数——这是跨组件但数据又"全局一点"的场景。
先试最省事的:把件数 state 提到一个公共父组件(页面根),购物车图标和详情按钮都从它拿 count 并通过回调递增。一两个组件这样做完全足够,这就是状态提升,成本最低、来源最清楚。
可当应用变大,详情页三层组件之下还有"加入购物车"按钮,中间那两层只是透传 count 和递增回调,props 就烦了。这时候要么用 Context(React)/ provide-inject(Vue)把"件数 + 加购操作"直接供给深层的按钮组件,要么直接上一个全局状态库(愿意为"多人共享 + 更多逻辑"持久化 6.1 的内容)。判断要诀仍是那句:透传链浅就提升,链深或共享多再升级。别一上来就 useState 满天飞、也别把小需求直接抬进状态库——两头的浪费都会写进日后维护的账单里。
通信不只是"传过去",更是立一份接口契约。父组件要传什么、子组件要接什么、谁是可选的,把它们在白纸黑字上写明,犯错的机会就会小很多。Vue 里这份契约写在 defineProps 的类型与默认值上,React 里则靠必填判断与一点约定:
<script setup> defineProps({ user: { type: Object, required: true }, size: { type: String, default: 'md' }, muted: { type: Boolean, default: false }, }); </script>
function Avatar({ user, size = 'md', muted = false }) { // 运行时若 user 没传,会得到 undefined —— 用默认值兜底 return <img src={muted ? user.mutedAvatar : user.avatar} className={`size-${size}`} />; }
为什么把这件事单独拿出来讲?因为组件不是为自己写的,而是被父组件、被迟早会接手的人、被三个月后忘了细节的自己使用。一份清晰的契约,等于把"你能给我什么、我给不了会怎样"写进代码,别人调用时看一眼签名就知道怎么用。反过来,prop 名起得含糊、可选值乱传,别人只能靠读子组件的全部实现来猜——这种隐式的契约是团队接口腐化的温床。
顺带一提物极必反:也别把每个 props 都堆满默认值和校验到"模板又臭又长"。契约的厚度要跟"谁在用它、多重要"匹配——深层共享的核心 props 值得写清楚默认值与类型,调一下就要出问题的必备 props 用 required 钉住;而那些随手传、无依赖细节的展示字段,写个平凡默认即可。契约的价值在可预期,不在长度。
父子通信讲完,另一个方向的复用来了——插槽。组件不仅要能接收 props,还要能被"装进任意内容"。下一节看插槽与内容分发。