vue3、react组件数据传值对比分析——父组件传递子组件,子组件传递父组件

文章目录

    • ⭐前言
    • ⭐react 组件传值实例
      • 💖父组件传值给子组件(props)
      • 💖子组件传递事件给父组件props绑定事件
      • 💖父组件触发子组件的事件Ref
    • ⭐vue3 组件传值实例
      • 💖 父组件传递数据给子组件props
      • 💖 子组件传递事件给父组件使用emit
      • 💖 父组件获取子组件实例使用Ref
    • ⭐总结
    • ⭐结束

yma16-logo

⭐前言

大家好,我是yma16,本文分享关于vue、react组件数据传值对比分析——父组件传递子组件,子组件传递父组件。
react渲染原理
React 是一个基于组件的 JavaScript 库,用于构建用户界面。React 的主要原理是将用户界面抽象为一组嵌套的组件,每个组件都拥有自己的状态和行为。当组件的状态发生改变时,React 会自动重新渲染组件,并将更新后的组件插入到 DOM 树中。

React 的渲染过程主要涉及以下几个步骤:

  1. 首先,React 会根据 JSX 语法解析出虚拟 DOM(Virtual DOM)对象树,该虚拟 DOM 对象树只是一个 JavaScript 对象,其中包含了组件的状态、属性和子节点等信息。

  2. 然后,React 通过比较新旧虚拟 DOM 对象树,找出需要更新的部分,只更新需要更新的部分,称之为 “DOM Diff”。

  3. 接着,React 调用 render 方法生成新的虚拟 DOM 对象树,并将其与旧的虚拟 DOM 对象树进行比较。

  4. 如果新旧虚拟 DOM 对象树相同,则不进行任何操作。

  5. 如果新旧虚拟 DOM 对象树不同,则根据差异进行更新,生成新的虚拟 DOM 对象树。

  6. 最后,React 将更新后的虚拟 DOM 对象树渲染到真实的 DOM 上,完成渲染过程。

React 的渲染过程主要基于虚拟 DOM 和差异化算法。通过虚拟 DOM 对象树的比较,React 能够高效地进行局部更新,提高了应用程序的性能和用户体验。
vue渲染原理
Vue的渲染原理可以大致分为以下几个步骤:

  1. 解析模板:Vue会将模板字符串解析成抽象语法树(AST),这个过程中会标记出模板中的所有指令、插值语法、事件等信息。这一步由模板编译器完成。

  2. 根据AST生成渲染函数:Vue会从抽象语法树中生成一个可执行的渲染函数(render function),这个函数可以接收一个参数——渲染上下文(render context),并返回一个VNode节点。

  3. 渲染函数执行:当组件需要重新渲染时,Vue会执行渲染函数,生成一个新的VNode节点树。

  4. Diff算法对比新旧VNode:Vue将上一步生成的新VNode节点树和上一次渲染的旧VNode节点树进行对比,通过Diff算法找出需要更新的节点。

  5. 生成补丁(patch):Diff算法找出需要更新的节点后,会生成一个补丁对象(patch),这个补丁对象描述了要对哪些节点进行何种修改操作。

  6. 将补丁应用到真实的DOM上:最后,Vue将生成的补丁对象应用到真实的DOM节点上,完成组件的更新。

注:以上是Vue2.x版本的渲染原理,Vue3.x版本的渲染原理有所不同,主要是采用了基于Proxy的响应式数据自动更新机制以及模板编译器与运行时渲染器分离等新特性。

⭐react 组件传值实例

项目截图
email-template

💖父组件传值给子组件(props)

App.tsx通过标签内属性传递editInstance给EmailPage.tsx

react-demo
父组件 App.txs
传递一个grapesjs实例到EmailPage

import './App.css';
import 'grapesjs/dist/css/grapes.min.css';
import grapesjs from 'grapesjs';function App() {return (<div className="App"><EmailPage editInstance={grapesjs} ></EmailPage></div>);
}export default App;

子组件 EmailPage.tsx 解构props
解构接收props的editorInstance

import grapesJSMJML  from '../components/email-edit/index'
import { forwardRef, useEffect, useState,useImperativeHandle } from 'react'const EmailPage=(props:any)=>{const [editor,setEditor]=useState();useEffect(()=>{const editorInstance:any = props.editInstance.init({fromElement: true,container: '#gjs-email',plugins: [grapesJSMJML ],});try{editorInstance.Commands.run('mjml-clear')}catch (e) {console.error('e',e)}setEditor(editorInstance)},[props.editInstance])return (<div id={'gjs-email'} className={'design-editor'}/>)
}export default EmailPage;

💖子组件传递事件给父组件props绑定事件

同理我们也可以在props传递一个事件给props,在子组价触发即可

💖父组件触发子组件的事件Ref

父组件 App.txs 使用ref获取组件实例

import './App.css';
import 'grapesjs/dist/css/grapes.min.css';
import grapesjs from 'grapesjs';
import { useState,useEffect,useRef } from 'react';function App() {const emailRef:any=useRef();useEffect(()=>{console.log(emailRef)},[emailRef])return (<div className="App"><EmailPage editInstance={grapesjs} ></EmailPage></div>);
}export default App;

子组件 EmailPage.txs使用useImperativeHandle 暴露方法和属性
暴露两个方法分别是 getHtml和getBodyContent,最后使用forwardRef抛出组件实例

import grapesJSMJML  from '../components/email-edit/index'
import { forwardRef, useEffect, useState,useImperativeHandle } from 'react'
import zh from "../components/email-edit/locale/zh";const EmailPage=(props:any,ref:any)=>{const [editor,setEditor]=useState();const [domRef,setDomRef]=useState();useEffect(()=>{const editorInstance:any = props.editInstance.init({fromElement: true,container: '#gjs-email',plugins: [grapesJSMJML ],});try{editorInstance.Commands.run('mjml-clear')}catch (e) {console.error('e',e)}setEditor(editorInstance)},[props.editInstance])const getBodyContent=()=>{// @ts-ignoreconst inlineHtml=editor.Commands.run('mjml-code-to-html-inline')const matchBody=new RegExp('<body[^>]*>([\\s\\S]+?)<\\/body>','ig');const matchBodyText=inlineHtml.match(matchBody)// @ts-ignorereturn matchBodyText?matchBodyText[0]:''};const getHtml=()=>{// @ts-ignorereturn editor.Commands.run('mjml-code-to-html-inline')}useImperativeHandle(ref, () => ({getHtml:getHtml,getBodyContent:getBodyContent}));return (<div id={'gjs-email'} className={'design-editor'}ref={(ref:any)=>{setDomRef(ref)}}/>)
}export default forwardRef(EmailPage);

⭐vue3 组件传值实例

项目截图
vue3-back-front

💖 父组件传递数据给子组件props

子组件 defineProps 定义接受的参数
IframeContent.vue

<template><div class="iframe-container"><div class="iframe-content" v-if="!isPage&&!isModel"><div style="width: 100%"><span> 标题:{{ title }} </span>{{kind}}<a-button@click="jumpPage"type="primary"style="float: right; margin: 5px">跳转</a-button></div><iframe :src="url" class="iframe-box"></iframe></div><div class="iframe-content" v-else-if="!isModel"><UserTable></UserTable></div><div class="iframe-content" v-else><ChatTable></ChatTable></div></div>
</template>
<script lang="ts" setup>import {computed} from 'vue'
// @ts-ignore
const props = defineProps<{url: string;title: string;kind: string;
}>();const isPage=computed(()=>{console.log('props',props)return props.kind=='page'
})const isModel=computed(()=>{console.log('props',props)return props.kind=='model'
})const emit = defineEmits<{(e: "change", id: number): void;(e: "update", value: string): void;
}>();
const jumpPage = () => {window.open(props.url);
};
</script>

父组件 标签内传递数据给子组件
传递参数给iframe-content组件

<script setup lang="ts">
// @ts-ignore
import IframeContent from "../iframe/IframeContent.vue";
import { reactive} from "vue";
interface contentType {url: string;title: string;kind:string;
}
const contentConfig: contentType = reactive({url: "url",title: "title",kind:'kind'
});</script><template><iframe-content:url="contentConfig.url":title="contentConfig.title":kind="contentConfig.kind"/>
</template>

💖 子组件传递事件给父组件使用emit

子组件

<template><div class="iframe-container"><div class="iframe-content" v-if="!isPage&&!isModel"><div style="width: 100%"><span> 标题:{{ title }} </span>{{kind}}<a-button@click="jumpPage"type="primary"style="float: right; margin: 5px">跳转</a-button></div><iframe :src="url" class="iframe-box"></iframe></div><div class="iframe-content" v-else-if="!isModel"><UserTable></UserTable></div><div class="iframe-content" v-else><ChatTable></ChatTable></div></div>
</template>
<script lang="ts" setup>import {computed} from 'vue'
// @ts-ignore
const props = defineProps<{url: string;title: string;kind: string;
}>();const isPage=computed(()=>{console.log('props',props)return props.kind=='page'
})const isModel=computed(()=>{console.log('props',props)return props.kind=='model'
})const emit = defineEmits<{(e: "change", id: number): void;(e: "update", value: string): void;
}>();
const jumpPage = () => {window.open(props.url);
};
</script>

父组件通过@绑定事件change和update就能接受子组件触发的change和update事件

💖 父组件获取子组件实例使用Ref

通过使用ref绑定formRef去获取校验事件

<template><div class="container"><div class="loginUser-container"><div class="loginUser-title">管理平台</div><a-form:model="state.formState":label-col="state.layoutConfig.labelCol":wrapper-col="state.layoutConfig.wrapperCol":rules="state.formRule"ref="formRef"layout="vertical"autocomplete="off"><a-form-item label="账号" name="username"><a-inputv-model:value="state.formState.username"allowClearplaceholder="请输入账号":disabled="state.spinning"/></a-form-item><a-form-item label="密码" name="password"><a-input-passwordv-model:value="state.formState.password":disabled="state.spinning"allowClearplaceholder="请输入密码"/></a-form-item><a-form-item name="remember" :wrapper-col="state.wrapperCol"><a-checkboxv-model:checked="state.formState.remember":disabled="state.spinning">记住密码</a-checkbox></a-form-item><a-form-item :wrapper-col="state.submitWrapperCol" class="submit-box"><a-buttontype="primary"html-type="submit"@click="loginAction":loading="state.spinning"style="width: 100%; font-size: 16px; font-weight: bolder">登录</a-button></a-form-item></a-form><div class="description"><span class="description-prefix">没账号?</span><span@click="jumpRegister"class="description-after":disabled="state.spinning">去注册</span></div></div></div>
</template>
<script lang="ts" setup>
import { reactive, ref, onMounted } from "vue";
import { useRouter } from "vue-router";
import { useStore } from "vuex";
import { message } from "ant-design-vue";
import { loginUser } from "../../service/user/userApi";import type { FormInstance } from "ant-design-vue";interface FormStateType {username: string;password: string;remember: boolean;
}
interface FormRuleType {username: Object;password: Object;
}
interface stateType {formState: FormStateType;formRule: FormRuleType;layoutConfig: any;wrapperCol: any;submitWrapperCol: any;spinning: boolean;backgroundImgUrl: string;
}
// 路由
const router = useRouter();
//store
const store = useStore();
const formRef = ref<FormInstance>();
const state: stateType = reactive({formState: {username: "",password: "",remember: false,},spinning: false,formRule: {username: [{ required: true, message: "请输入账号!" }],password: [{ required: true, message: "请输入密码!" }],},layoutConfig: {labelCol: {span: 8,},wrapperCol: {span: 24,},},wrapperCol: { offset: 0, span: 24 },submitWrapperCol: { offset: 0, span: 24 },backgroundImgUrl:"http://www.yongma16.xyz/staticFile/common/img/background.png",
});
/*** 初始化表单内容*/
const initForm = () => {const userInfoItem: any = window.localStorage.getItem("userInfo");interface userInfoType {username: string;password: string;remember: boolean;}const userInfo: userInfoType = userInfoItem? JSON.parse(userInfoItem): {username: "",password: "",remember: false,};if (userInfo.username && userInfo.password) {state.formState.username = userInfo.username;state.formState.password = userInfo.password;state.formState.remember = userInfo.remember;}
};
/*** 前往注册!*/
const jumpRegister = () => {// 带 hash,结果是 /about#teamrouter.push({ path: "/register" });
};/*** 前往home!*/
const jumpHome = () => {// 带 hash,结果是 /about#teamrouter.push({ path: "/" });
};
/*** 记住密码* @param params*/
const rememberAction = (params: Object) => {window.localStorage.setItem("userInfo", JSON.stringify(params));
};
/*** 登录*/
const loginAction = () => {if (formRef.value) {formRef.value.validate().then(async (res: any) => {state.spinning = true;const params = {username: state.formState.username,password: state.formState.password,};if (state.formState.remember) {rememberAction({ ...params, remember: state.formState.remember });}try {console.log('登录',params)// @ts-ignoreawait store.dispatch("user/loginUser",params);// 跳转setTimeout(() => {jumpHome();}, 500);state.spinning = false;} catch (r: any) {message.error(JSON.stringify(r));state.spinning = false;throw Error(r);}});}
};onMounted(() => {//初始化initForm();
});
</script>

⭐总结

综合比较react和vue,对于选型我分成两种情况讨论。

  1. vue项目选型——vue3 vben admin
    a. 外包项目(可维护性强,中文文档多,容错率高)
    b. 国内开发者众多的团队,因为vue中文文档比较多
    c. 使用vue较多的团队,适合快速上手
  2. react项目——qiankun
    a. 自研大型项目(个人觉得react项目不好抄袭)
    b. 外企团队,因为react的文档大部分都是英文
    c. 使用react较多的团队,适合快速上手

个人比较看好vue,有以下3点。
a. 国内开发人数众多,搭建可以用中文在社区交流vue3,扩大国内开发影响力
b. vue3的组件传值等我都比react好用,react用的费劲
c. vue的生态良好,版本也一直在迭代更新

⭐结束

本文分享到这结束,如有错误或者不足之处欢迎指出!
cute-animal

👍 点赞,是我创作的动力!
⭐️ 收藏,是我努力的方向!
✏️ 评论,是我进步的财富!
💖 感谢你的阅读!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/45638.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【论文阅读】SHADEWATCHER:使用系统审计记录的推荐引导网络威胁分析(SP-2022)

SHADEWATCHER: Recommendation-guided CyberThreat Analysis using System Audit Records S&P-2022 新加坡国立大学、中国科学技术大学 Zengy J, Wang X, Liu J, et al. Shadewatcher: Recommendation-guided cyber threat analysis using system audit records[C]//2022 I…

学C的第三十四天【程序环境和预处理】

相关代码gitee自取&#xff1a; C语言学习日记: 加油努力 (gitee.com) 接上期&#xff1a; 学C的第三十三天【C语言文件操作】_高高的胖子的博客-CSDN博客 1 . 程序的翻译环境和执行环境 在ANSI C(C语言标准)的任何一种实现中&#xff0c;存在两个不同的环境。 &#xff0…

容器虚拟化基础之cgroups/LXC

"你真的&#xff0c;自由了~" 容器虚拟化基础之Cgroups: (1) 什么是cgroups cgroups是 linux 内核提供的一种机制&#xff0c; 这种机制可以根据需求把一系列系统任务及其子任务整合(或分隔)到按资源划分等级的不同组内&#xff0c;从而为系统资源管理提供一个统一…

3D与沉浸式技术,如何助力企业数字化转型?

说起3D&#xff0c;估计许多读者朋友会在第一时间想起《阿凡达》系列和《侏罗纪公园》系列电影大作。每一帧细节纤毫毕现的逼真画面&#xff0c;让观众几乎分不清虚拟与现实&#xff0c;完全沉浸在导演打造的视觉盛宴中。 事实上&#xff0c;除了大家所熟知的3D影视动画之外&am…

快速学习GO语言总结

备注&#xff1a;本博客将自己初步学习GO的总结进行分享&#xff0c;希望大家通过本博客可以在短时间内快速掌握GO的基本程序编码能力&#xff0c;如有错误请留言指正&#xff0c;谢谢&#xff01; 一、初步了解Go语言 &#xff08;一&#xff09;Go语言诞生的主要问题和目标…

iOS17 widget Content margin

iOS17小组件有4个新的地方可以放置分别是&#xff1a;Mac桌面、iPad锁屏界面、 iPhone Standby模式、watch的smart stack Transition to content margins iOS17中苹果为widget新增了Content margin, 使widget的内容能够距离边缘有一定的间隙&#xff0c;确保内容显示完整。这…

学习设计模式之适配器模式,但是宝可梦

前言 作者在准备秋招中&#xff0c;学习设计模式&#xff0c;做点小笔记&#xff0c;用宝可梦为场景举例&#xff0c;有错误欢迎指出。 适配器模式 意图&#xff1a;将一个类的接口转换成客户希望的另一个接口 主要解决&#xff1a;把现有对象放到新环境里&#xff0c;而新…

IDEA 如何制作代码补丁?IDEA 生成 patch 和使用 patch

什么是升级补丁&#xff1f; 比如你本地修复的 bug&#xff0c;需要把增量文件发给客户&#xff0c;很多场景下大家都需要手工整理修改的文件&#xff0c;并整理好目录&#xff0c;这个很麻烦。那有没有简单的技巧呢&#xff1f;看看 IDEA 生成 patch 和使用 patch 的使用。 介…

一、Kafka概述

目录 1.3 Kafka的基础架构 1.3 Kafka的基础架构 Producer&#xff1a;消息生产者&#xff0c;就是向 Kafka broker 发消息的客户端Consumer&#xff1a;消息消费者&#xff0c;向 Kafka broker 取消息的客户端。Consumer Group&#xff08;CG&#xff09;&#xff1a;消费者组&…

PyTorch学习笔记(十六)——利用GPU训练

一、方式一 网络模型、损失函数、数据&#xff08;包括输入、标注&#xff09; 找到以上三种变量&#xff0c;调用它们的.cuda()&#xff0c;再返回即可 if torch.cuda.is_available():mynn mynn.cuda() if torch.cuda.is_available():loss_function loss_function.cuda(…

SpringMVC之@RequestMapping注解

文章目录 前言一、RequestMapping介绍二、详解&#xff08;末尾附源码&#xff0c;自行测试&#xff09;1.RequestMapping注解的位置2.RequestMapping注解的value属性3.RequestMapping注解的method属性4.RequestMapping注解的params属性&#xff08;了解&#xff09;5.RequestM…

华为ENSP网络设备配置实战6(简单的链路聚合)

题目要求 1、创建聚合组&#xff0c;添加端口成员 2、PC1网段为vlan10&#xff0c;PC2网段为vlan20 3、LSW1为核心网关设备&#xff0c;正确配置PC网关 4、PC1与PC2互通 解题过程 1.1、 按照拓扑图&#xff0c;各个设备起名 sys &#xff08;进入系统视图&#xff09; sy…

TCP协议报文结构

TCP是什么 TCP&#xff08;传输控制协议&#xff09;是一种面向连接的、可靠的、全双工的传输协议。它使用头部&#xff08;Header&#xff09;和数据&#xff08;Data&#xff09;来组织数据包&#xff0c;确保数据的可靠传输和按序传递。 TCP协议报文结构 下面详细阐述TCP…

FRP内网穿透,配置本地电脑作为服务器

FRP内网穿透&#xff0c;配置本地电脑作为服务器 下载FRP服务端客户端 参考链接&#xff1a; https://www.it235.com/实用工具/内网穿透/pierce.html https://www.cnblogs.com/007sx/p/17469301.html 由于没有公网ip&#xff0c;所以尝试内网穿透将本地电脑作为服务器&#xff…

【Mariadb高可用MHA】

目录 一、概述 1.概念 2.组成 3.特点 4.工作原理 二、案例介绍 1.192.168.42.3 2.192.168.42.4 3.192.168.42.5 4.192.168.42.6 三、实际构建MHA 1.ssh免密登录 1.1 所有节点配置hosts 1.2 192.168.42.3 1.3 192.168.42.4 1.4 192.168.42.5 1.5 192.168.42.6 …

(二)结构型模式:7、享元模式(Flyweight Pattern)(C++实例)

目录 1、享元模式&#xff08;Flyweight Pattern&#xff09;含义 2、享元模式的UML图学习 3、享元模式的应用场景 4、享元模式的优缺点 5、C实现享元模式的简单实例 1、享元模式&#xff08;Flyweight Pattern&#xff09;含义 享元模式&#xff08;Flyweight&#xff09…

OpenCV笔记之solvePnP函数和calibrateCamera函数对比

OpenCV笔记之solvePnP函数和calibrateCamera函数对比 文章目录 OpenCV笔记之solvePnP函数和calibrateCamera函数对比1.cv::solvePnP2.cv::solvePnP函数的用途和工作原理3.cv::solvePnP背后的数学方程式4.cv::SOLVEPNP_ITERATIVE、cv::SOLVEPNP_EPNP、cv::SOLVEPNP_P3P5.一个固定…

为什么需要单元测试?

为什么需要单元测试&#xff1f; 从产品角度而言&#xff0c;常规的功能测试、系统测试都是站在产品局部或全局功能进行测试&#xff0c;能够很好地与用户的需要相结合&#xff0c;但是缺乏了对产品研发细节&#xff08;特别是代码细节的理解&#xff09;。 从测试人员角度而言…

Qt应用开发(基础篇)——纯文本编辑窗口 QPlainTextEdit

一、前言 QPlainTextEdit类继承于QAbstractScrollArea&#xff0c;QAbstractScrollArea继承于QFrame&#xff0c;是Qt用来显示和编辑纯文本的窗口。 滚屏区域基类https://blog.csdn.net/u014491932/article/details/132245486?spm1001.2014.3001.5501框架类QFramehttps://blo…

Elasticsearch复合查询之Boosting Query

前言 ES 里面有 5 种复合查询&#xff0c;分别是&#xff1a; Boolean QueryBoosting QueryConstant Score QueryDisjunction Max QueryFunction Score Query Boolean Query在之前已经介绍过了&#xff0c;今天来看一下 Boosting Query 用法&#xff0c;其实也非常简单&…