跳转到内容

Props / Callback 与 props / emit

同一个“子组件输入消息、父组件接收结果”的 Demo。重点看 React 如何把函数当作 props 传入,以及 Vue 如何声明并触发组件事件。

React

回调函数作为 props,由子组件主动调用。

在线预览

Parent

组件通信

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

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

组件关系与数据流

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:#ffffff,stroke:#149eca,color:#172033,stroke-width:1.2px
  classDef component fill:#e5f6fb,stroke:#149eca,color:#172033,stroke-width:2px,font-weight:600
  classDef process fill:#f4fbfd,stroke:#149eca,color:#172033,stroke-width:1.6px
  classDef resource fill:#f3f5f8,stroke:#778195,color:#172033,stroke-width:1.4px

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

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

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

实际运行源码

import { useState } from "react";
type MessageInputProps = {
onSend: (message: string) => void;
};
function MessageInput({ onSend }: MessageInputProps) {
const [value, setValue] = useState("");
function handleSubmit(event: React.FormEvent<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

父组件监听子组件通过 emit 发出的事件。

在线预览

Parent

组件通信

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

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

组件关系与数据流

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:#ffffff,stroke:#42b883,color:#172033,stroke-width:1.2px
  classDef component fill:#e7f8f0,stroke:#42b883,color:#172033,stroke-width:2px,font-weight:600
  classDef process fill:#f2fbf7,stroke:#42b883,color:#172033,stroke-width:1.6px
  classDef resource fill:#f3f5f8,stroke:#778195,color:#172033,stroke-width:1.4px

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

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

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

实际运行源码

<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>