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

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

⭐前言

大家好,我是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 组件传值实例

项目截图

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

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

父组件 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-ignore
        const inlineHtml=editor.Commands.run('mjml-code-to-html-inline')
        const matchBody=new RegExp('<body[^>]*>([\\s\\S]+?)<\\/body>','ig');
        const matchBodyText=inlineHtml.match(matchBody)
        // @ts-ignore
        return matchBodyText?matchBodyText[0]:''
    };
    const getHtml=()=>{
        // @ts-ignore
        return 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 组件传值实例

项目截图

💖 父组件传递数据给子组件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>


vue3、react组件数据传值对比分析——父组件传递子组件,子组件传递父组件(二)https://developer.aliyun.com/article/1492685


目录
相关文章
|
9天前
|
前端开发
如何在React Router中定义404错误页面组件?
如何在React Router中定义404错误页面组件?
75 57
|
9天前
|
前端开发
在 React 中使用高阶组件时,如何避免命名冲突?
在 React 中使用高阶组件时,如何避免命名冲突?
71 56
|
2天前
|
移动开发 前端开发 JavaScript
React音频播放列表组件:常见问题、易错点与解决方案
本文介绍了在React中实现音频播放列表时常见的挑战及解决方案。通过基础实现、常见问题分析和最佳实践,帮助开发者避免状态管理、生命周期控制和事件处理中的陷阱。关键点包括使用`useRef`操作音频元素、`useState`同步播放状态、全局状态管理防止多音频同时播放、以及通过`useEffect`清理资源。还提供了代码示例和跨浏览器兼容性处理方法,确保高效实现功能并减少调试时间。
66 30
|
4天前
|
移动开发 前端开发 UED
React 音频音量控制组件 Audio Volume Control
在现代Web应用中,音频播放功能不可或缺。React以其声明式编程和组件化开发模式,非常适合构建复杂的音频音量控制组件。本文介绍了如何使用HTML5 `&lt;audio&gt;`元素与React结合,实现直观的音量控制系统,并解决了常见问题如音量范围不合理、初始音量设置及性能优化等,帮助开发者打造优秀的音频播放器。
56 27
|
6天前
|
移动开发 前端开发 开发者
React 音频播放控制组件 Audio Controls
本文介绍了如何使用React构建音频播放控制组件,涵盖HTML5 `&lt;audio&gt;`标签和React组件化思想的基础知识。针对常见问题如播放状态管理、进度条更新不准确及跨浏览器兼容性,提供了详细的解决方案和代码示例。同时,还总结了易错点及避免方法,如确保音频加载完成再操作、处理音频错误等,帮助开发者实现稳定且功能强大的音频播放器。
38 11
|
5天前
|
移动开发 前端开发 UED
React 音频进度条组件 Audio Progress Bar
在现代Web开发中,音频播放功能不可或缺。使用React构建音频进度条组件,不仅能实现播放控制和拖动跳转,还能确保代码的可维护性和复用性。本文介绍了如何利用HTML5 `&lt;audio&gt;`标签的基础功能、解决获取音频时长和当前时间的问题、动态更新进度条样式,并避免常见错误如忘记移除事件监听器和忽略跨浏览器兼容性。通过这些方法,开发者可以打造高质量的音频播放器,提升用户体验。
36 6
|
9天前
|
前端开发
React 中高阶组件的原理是什么?
React 中高阶组件的原理是什么?
83 57
|
9天前
|
前端开发 JavaScript
除了使用Route组件,React Router还有其他方式处理404错误页面吗
除了使用Route组件,React Router还有其他方式处理404错误页面吗
|
12天前
|
人工智能 自然语言处理 前端开发
Flame:开源AI设计图转代码模型!生成React组件,精准还原UI+动态交互效果
Flame 是一款开源的多模态 AI 模型,能够将 UI 设计图转换为高质量的现代前端代码,支持 React 等主流框架,具备动态交互、组件化开发等功能,显著提升前端开发效率。
261 1
|
9天前
|
前端开发 开发者
除了函数组件和类组件,React 还有其他创建组件的方式吗?
除了函数组件和类组件,React 还有其他创建组件的方式吗?