React × Vue

Props / Callback 与 props / emit

React 通过 props 传值并用回调向上传递事件;Vue 使用 props 与 emit 表达同样的数据流。

核心结论

两边都遵循单向数据流:父组件通过 props 向下传值,子组件通过一个明确的通知边界请求父组件更新。React 把通知表示成函数 prop,Vue 把它表示成组件事件。

数据流

组件关系与数据流

StateComponent

差异焦点Callback 是普通函数 prop,子组件知道并直接调用它。

实线表示依赖、数据或命令传递,虚线表示事件、回调或清理路径。

flowchart TB
  accTitle: React 回调属性通信机制
  accDescr: ReactDemo 把函数作为 onSend prop 传给 MessageInput,子组件直接调用函数,setMessage 调度父组件重新渲染。
  parent["ReactDemo"] -->|"传入 onSend 函数 prop"| child["MessageInput"]
  input(["value state"]) --> child
  child -.->|"直接调用 onSend(message)"| setter{{"setMessage"}}
  setter --> message(["message state"])
  message -->|"重新渲染"| parent
  class input,message state
  class parent,child component
  class setter process
  classDef state fill:#fffdf8,stroke:#149eca,color:#25221d,stroke-width:1.2px
  classDef component fill:#e4f5fa,stroke:#149eca,color:#25221d,stroke-width:2px,font-weight:600
  classDef process fill:#f4fafb,stroke:#149eca,color:#25221d,stroke-width:1.6px
  classDef resource fill:#eee9df,stroke:#817a70,color:#25221d,stroke-width:1.4px

函数作为 props 向下传递;子组件调用函数后,setter 调度父组件重新渲染。

React 流程图
React 组件关系与数据流

滚轮缩放 · 按住拖动 · 双击重置 · Esc 关闭

组件关系与数据流

StateComponent

差异焦点emit 是显式事件协议,子组件不直接持有父组件函数。

实线表示依赖、数据或命令传递,虚线表示事件、回调或清理路径。

flowchart TB
  accTitle: Vue 声明式组件事件机制
  accDescr: MessageInput 通过 defineEmits 声明 send 事件并 emit,VueDemo 使用事件监听器接收 payload 后修改 message ref。
  input(["value ref"]) --> child["MessageInput"]
  child --> contract{{"defineEmits 声明 send"}}
  contract -.->|"emit send(message)"| listener{{"VueDemo @send 监听器"}}
  listener --> message(["message ref"])
  message --> parent["VueDemo"]
  class input,message state
  class child,parent component
  class contract,listener process
  classDef state fill:#fffdf8,stroke:#2f9d6b,color:#25221d,stroke-width:1.2px
  classDef component fill:#e4f4eb,stroke:#2f9d6b,color:#25221d,stroke-width:2px,font-weight:600
  classDef process fill:#f2f8f4,stroke:#2f9d6b,color:#25221d,stroke-width:1.6px
  classDef resource fill:#eee9df,stroke:#817a70,color:#25221d,stroke-width:1.4px

子组件声明事件协议并 emit;父组件通过模板监听器接收 payload。

Vue 3 流程图
Vue 3 组件关系与数据流

滚轮缩放 · 按住拖动 · 双击重置 · Esc 关闭

完整 Demo 源码

以下代码直接读取在线 Demo 使用的源文件,没有省略或改写。

React 源码

ReactDemo.tsx
import { useState } from "react";type MessageInputProps = {  onSend: (message: string) => void;};function MessageInput({ onSend }: MessageInputProps) {  const [value, setValue] = useState("");  function handleSubmit(event: React.SubmitEvent<HTMLFormElement>) {    event.preventDefault();    const message = value.trim();    if (!message) return;    onSend(message);    setValue("");  }  return (    <form className="demo-form" onSubmit={handleSubmit}>      <label className="demo-field">        子组件输入        <input          className="demo-input"          value={value}          placeholder="输入一条消息"          onChange={(event) => setValue(event.target.value)}        />      </label>      <div className="demo-actions">        <button className="demo-button" type="submit">          发送给父组件        </button>      </div>    </form>  );}export function ReactDemo() {  const [message, setMessage] = useState("还没有收到消息");  return (    <div className="demo-stack">      <div className="demo-card">        <span className="demo-tag">Parent</span>        <h2>组件通信</h2>        <p>父组件把 onSend 回调交给子组件。</p>      </div>      <MessageInput onSend={setMessage} />      <p className="demo-result" aria-live="polite">        父组件收到:{message}      </p>    </div>  );}

Vue 3 源码

<script setup lang="ts">import { ref } from "vue";import MessageInput from "./MessageInput.vue";const message = ref("还没有收到消息");</script><template>  <div class="demo-stack">    <div class="demo-card">      <span class="demo-tag">Parent</span>      <h2>组件通信</h2>      <p>父组件监听子组件触发的 send 事件。</p>    </div>    <MessageInput @send="message = $event" />    <p class="demo-result" aria-live="polite">父组件收到:{{ message }}</p>  </div></template>

在线观察

在子组件中输入消息并发送,父组件负责保存最终结果。

React

Parent

组件通信

父组件把 onSend 回调交给子组件。

父组件收到:还没有收到消息

Vue 3

Parent

组件通信

父组件监听子组件触发的 send 事件。

父组件收到:还没有收到消息

设计边界

  • 子组件不应直接修改父组件拥有的状态。
  • React 的 onSend 只是普通函数;Vue 的 send 是组件公开事件协议。
  • 回调引用是否需要稳定属于性能问题,不属于通信机制本身,见useCallback。
  • 跨越很多组件层级时,再考虑Context 与 provide/inject。