稀土掘金技术社区 02月08日
你知道的“React18与Vue3组件通信”都在这
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

本文深入对比了React18和Vue3在组件通信方面的异同,重点分析了父子组件、兄弟组件以及跨层组件的通信方式。针对父子组件通信,React18通过props传递数据,Vue3则使用defineProps声明接收。兄弟组件通信,两者都采用状态提升到父组件的方式。跨层组件通信方面,React18使用Context API,Vue3则采用provide/inject API。文章旨在帮助开发者更好地理解和选择适合自己项目的通信方案,简化组件结构和数据流动。

👶**父子组件通信**:React18中,父组件通过props向子组件传递数据,子组件通过props对象接收;Vue3中,父组件使用v-bind动态绑定数据到子组件的props,子组件使用defineProps声明接收的props。

🤝**兄弟组件通信**:React和Vue都采用将共享状态提升到父组件的方式。React中,父组件定义函数修改状态,并通过props传递给子组件;Vue中,父组件通过props向子组件传递数据,子组件通过emit向父组件传递事件。

🏢**跨层组件通信**:React使用Context API,通过createContext创建context对象,Provider提供数据,useContext钩子接收数据;Vue3使用provide/inject API,provide在父组件提供数据,inject在后代组件获取数据。Vue3还可以使用pinia🍍全局管理共享数据store

原创 ys指风不买醉 2025-02-06 08:30 重庆

点击关注公众号,“技术干货” 及时达!

前言

经过Vue3的洗礼,最近初始React18,还是觉得有必要对比一下两者进行通信的方式。主要以 ‘父子通信’,‘兄弟通信’,‘跨域通信’进行展开

文章有点长,可以收藏起来,慢慢看~~  但是不要让这篇文章吃灰·哦·

01| 父子组件通信

React18

1.父传子

function App() {    return (        <div>            <Son1 name="李四" age={20} />        </div>    );}function Son1(props) {    return (        <div>            <h2>姓名:{props.name}</h2>            <h2>年龄:{props.age}</h2>            <h2>内容:{props.children}</h2>        </div>    );}

这里props.children,因为页面有「显示」props从父组件传递的内容,就为空

但是props.children 是一个很重要react里面重要概念。这里插入简单讲一下

props.children 允许你在组件中嵌套和传递子组件的内容。children 是一个特殊的 prop,它包含了组件标签内的所有子节点,无论是文本、元素还是其他组件。

当你在父组件中使用子组件时,如果没有显式传递某些内容,props.children 会自动接收子组件标签内的内容。

2.子传父

    「父组件定义一个函数」,用于接收子组件传递的数据。

    「父组件将函数通过 props 传递给子组件」

    「子组件调用该函数」,并将数据作为参数传递给父组件。

import React, { useState } from 'react';
function Parent() { const [msg, setMsg] = useState('');
// 父组件定义的回调函数,用于接收子组件传递的数据 const handleMsg = (msg) => { setMsg(msg); };
return ( <div> <h2>父组件状态:{msg}</h2> {/* 将回调函数通过 props 传递给子组件 */} <Son1 handleMsg={handleMsg} /> </div> );}// 解构function Son1({ handleMsg }) { const sonMsg = '我是Son1子组件';
// 子组件调用父组件传递的回调函数,并传递数据 return <button onClick={() => handleMsg(sonMsg)}>点击传递消息</button>;}


Vue3

1. 父传子

在 Vue 3 中,父组件通过 props 向子组件传递数据,子组件通过 defineProps 来声明接收的 props

<template>  <!-- 使用‘v-bind:name’将父组件中的parentName变量的值动态绑定到子组件的 `name` 属性上-->  <Son :name="parentName" :age="parentAge" /></template>
<script setup>import { ref } from 'vue';import Son from './Son.vue';
const parentName = ref('李四');const parentAge = ref(20);</script>
<!-- Son.vue --><template>  <div>    <h2>姓名:{{ name }}</h2>    <h2>年龄:{{ age }}</h2>  </div></template>
<script setup>// 子组件 defineProps 进行接收defineProps({ name: { type: String, required: true } age: Number});</script>

「问:如何在父组件调用子组件时传递方法,并让父组件获取子组件内部的方法或属性?」

子组件需要明确地暴露这些方法和属性。这可以通过使用 defineExpose 来实现。随后,父组件可以通过 reftemplate ref 来引用子组件实例,从而调用其暴露的方法或访问其属性。

具体步骤如下:

    「子组件暴露方法和属性」

    在子组件中,使用 defineExpose 来指定哪些方法或属性应该被父组件访问。

「父组件引用子组件」

    父组件通过 ref 或 template ref 获取对子组件实例的引用。

    一旦子组件挂载完成,父组件就可以通过这个引用来调用子组件的方法或读取其属性。

「父组件向子组件传递方法」

    如果需要从父组件向子组件传递方法,可以通过 props 实现。子组件可以接收这些方法并通过 emit 触发事件来回调父组件的方法。(后文兄弟通信,也使用到)

// 子组件<template>    <div>        <h1>Hello child!</h1>    </div></template>
<script setup>import { defineExpose } from 'vue';// 暴露出去defineExpose({ foo() { console.log('这是来自子组件的foo方法'); }, childName:'这是子组件的属性'})</script>
//父组件<template>    <div>        <Child ref="cmp"/> <!-- 模版中标记,直接访问dom元素,或是子组件的实例 -->        <button @click="handleClick">按钮</button>    </div></template>
<script setup>import {ref} from 'vue'import Child from './Child.vue';
const cmp = ref(null); // null表示未挂载function handleClick() { cmp.value.foo(); cmp.value.childName = '修改了子组件的属性'; console.log(cmp.value);}</script>

当子组件方法或是属性发生变化,父组件能够ref自动更新。相当于子组件挂载完毕后,使用ref响应式引用,父组件就可以在需要时调用其方法或访问其属性。注意ref拿值时,得.value

2. 子传父

在 Vue 3 中,子组件通过 $emit 向父组件发送事件,父组件通过 v-on 监听该dom事件。使用defineEmit或是thia.$emit将子组件的方法或是属性传递给父组件使用。

<!-- Parent.vue --><template>  <!-- @ v-on 简写,使用 v-on 监听子组件的 sendMessage 事件 -->  <Son @sendMessage="receiveMessage" />  <p>{{ message }}</p></template>
<script setup>import { ref } from 'vue';import Son from './Son.vue';
const message = ref('');
function receiveMessage(msg) { message.value = msg;}</script>
<!-- Son.vue --><template>  <button @click="sendMessage">点击传递消息</button></template>
<script setup>const emit = defineEmits();
function sendMessage() { // 触发 'sendMessage' 事件,并传递消息作为参数 emit('sendMessage', '我是Son组件');}</script>

上面defineEmits() 不用声明事件,可以传递任何事件,但同时也失去了对事件的类型检查和编译时验证。多项目中,未知事件传递带来风险。下面采用「对象和数组」两种方式简单说明,defineEmits()可以进行的检查和编译

数组形式示例

    const emit = defineEmits(['sendMessage', 'updateData', 'closeModal']);

对象形式示例(TypeScript)

<script setup lang="ts">interface Emit {  (e: 'sendMessage', message: string): void;  (e: 'updateData', id: number, data: object): void;  (e: 'closeModal'): void;}
// 明确声明可以发射的事件,并提供类型检查const emit = defineEmits<Emit>();
</script>

02| 跨层组件通信:使用 context VS provide 实现

跨层通信由父App组件传给A里面的B组件

React

在 React 中,跨层组件通信可以通过 「Context API」 来实现。Context 允许你在组件树中传递数据,而不必手动通过每一层的 props。这种机制对于需要跨越多层嵌套的组件来说非常有用。

import React, { createContext, useContext } from 'react';
// 1. 创建 context 对象const MsgContext = createContext();function ContextApp() { const msg = 'this is app';
return ( <> {/* 2. 使用 Provider 包裹组件并提供数据 */} <MsgContext.Provider value={msg}> <div> <h2>我是 App 组件</h2> <A /> </div> </MsgContext.Provider> </> );}function A() { const sonMsg = '我是 son1 子组件'; return ( <> {sonMsg} <B /> </> );}function B() { // 3. 使用 useContext 钩子接收数据 const msg = useContext(MsgContext); return ( <> <div>this is B,{msg}</div> </> );}export default ContextApp;

Vue 3

在 Vue 3 中,跨层组件通信可以通过 provideinject API 来实现。provide 用于提供数据,而 inject 用于在后代组件中获取这些数据。这是 Vue 中实现跨层组件通信的标准方法(其实也可以使用pinia?全局管理共享数据store)

<!-- Parent.vue --><template>  <div>    <h2>我是 App 组件</h2>    <A />  </div></template>
<script setup>import { provide } from 'vue';import A from './A.vue';
const msg = 'this is app';
// 1. 使用 provide 提供数据provide('msg', msg);</script>
<!-- A.vue --><template>  <div>    我是 son1 子组件    <B />  </div></template>
<script setup>import B from './B.vue';</script>
<!-- B.vue --><template>  <div>    this is B,{{ msg }}  </div></template>
<script setup>import { inject } from 'vue';
// 2. 使用 inject 获取数据const msg = inject('msg');</script>

对比:React 与 Vue 的跨层通信

特性ReactVue 3
「跨层通信方式」contextuseContextprovideinject
「数据传递方向」Provider 向下传递数据, Consumer 获取数据provide 在父组件提供数据, inject 在后代组件获取数据
「适用场景」适用于中等规模应用,尤其是需要共享全局状态时适用于需要跨越多个层级传递数据的场景

03| 兄弟组件通信

React

兄弟组件的通信通过将「共享的状态提升」到父组件来实现。父组件将该状态和修改状态的函数通过 props 传递给子组件。

import React, { useState } from 'react';function Parent() {    const [msg, setMsg] = useState('');
const getMsg = (msg) => { setMsg(msg); };
return ( <div> <h2>父组件状态:{msg}</h2> <Son1 getMsg={getMsg} /> <Son2 msg={msg} /> </div> );}
function Son1({ getMsg }) { const sonMsg = '我是Son1子组件'; return <button onClick={() => getMsg(sonMsg)}>传递消息</button>;}
function Son2({ msg }) { return <h2>兄弟组件接收到的消息:{msg}</h2>;}

Vue

在 Vue 3 中,兄弟组件的通信也通过将共享的状态提升到父组件来实现。父组件通过 props 向子组件传递数据,子组件通过 emit 向父组件传递事件。

<!-- Parent.vue --><template>  <Son1 @sendMessage="receiveMessage" />  <Son2 :msg="message" /></template>
<script setup>import { ref } from 'vue';import Son1 from './Son1.vue';import Son2 from './Son2.vue';
const message = ref('');
function receiveMessage(msg) { message.value = msg;}</script>

<!-- Son1.vue --> <template> <button @click="sendMessage">传递消息</button> </template>
<script setup> const emit = defineEmits();
function sendMessage() { emit('sendMessage', '我是Son1子组件'); } </script>
    <!-- Son2.vue -->    <template>      <h2>兄弟组件接收到的消息:{{ msg }}</h2>    </template>
<script setup> defineProps({ msg: String, required:true // 必须传 }); </script>

总结

React18和Vue3 机制都是为了简化,Vue3哲学注重业务开发,所以通过很多对应的语法。比如,props接收参数,'v-bind'等。React18 适合大型项目,在管理项目和JavaScript运用上面都有深入。就以跨层组件通信来说,通过 「Context」(React)或 provide/inject(Vue 3) API,开发者可以更加方便地进行跨层组件通信,尤其是当数据需要在深层嵌套的组件间共享时,能极大简化组件的结构和数据流动。

点击关注公众号,“技术干货” 及时达!

阅读原文

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

React18 Vue3 组件通信 Context API provide/inject
相关文章