手写一个react,看透react运行机制

本文适合0.5~3年经验的React开发者,通过讲解jsx、虚拟DOM和源码,帮助理解React执行过程。作者强调React源码比Vue更难,但适合初学者进阶。文章介绍了jsx的转换原理,虚拟DOM的重要性,以及React和ReactDOM如何协作完成渲染。此外,还详细阐述了手动实现React的基本步骤,包括jsx转换、虚拟DOM构建、ReactDOM.render和组件化。最后,简要展示了手写React的源码片段。
摘要由CSDN通过智能技术生成

适合人群

本文适合0.5~3年的react开发人员的进阶。

讲讲废话:

react的源码,的确是比vue的难度要深一些,本文也是针对初中级,本意让博友们了解整个react的执行过程。

写源码之前的必备知识点

JSX

首先我们需要了解什么是JSX。

网络大神的解释:React 使用 JSX 来替代常规的 JavaScript。JSX 是一个看起来很像 XML 的 JavaScript 语法扩展。

是的,JSX是一种js的语法扩展,表面上像HTML,本质上还是通过babel转换为js执行。再通俗的一点的说,jsx就是一段js,只是写成了html的样子,而我们读取他的时候,jsx会自动转换成vnode对象给我们,这里都由react-script的内置的babel帮助我们完成。

简单举个栗子:

return (
  <div>
    Hello  Word  </div>
)

实际上是:

return React.createElement(
  "div",
  null,
  "Hello"
)


JSX本质上就是转换为React.createElement在React内部构建虚拟Dom,最终渲染出页面。

相关参考视频讲解:进入学习

虚拟Dom

这里说明一下react的虚拟dom。react的虚拟dom跟vue的大为不同。vue的虚拟dom是为了是提高渲染效率,而react的虚拟dom是一定需要。很好理解,vue的template本身就是html,可以直接显示。而jsx是js,需要转换成html,所以用到虚拟dom。

我们描述一下react的最简版的vnode:

function createElement(type, props, ...children) {
   
  props.children = children;
  return {
   
    type,
    props,
    children,
  };
}

这里的vnode也很好理解,
type表示类型,如div,span,
props表示属性,如{id: 1, style:{color:red}},
children表示子元素
下边会在createElement继续讲解。

原理简介

我们写一个react的最简单的源码:

import React from 'react'
import ReactDOM from 'react-dom'
function App(props){
   
     return <div>你好</div>
 </div>
}
ReactDOM.render(<App/>,  document.getElementById('root'))

  • React负责逻辑控制,数据 -> VDOM
    首先,我们可以看到每一个js文件中,都一定会引入import React from ‘react’。但是我们的代码里边,根本没有用到React。但是你不引入他就报错了。

为什么呢?可以这样理解,在我们上述的js文件中,我们使用了jsx。但是jsx并不能给编译,所以,报错了。这时候,需要引入react,而react的作用,就是把jsx转换为“虚拟dom”对象。

JSX本质上就是转换为React.createElement在React内部构建虚拟Dom,最终渲染出页面。而引入React,就是为了时限这个过程。

  • ReactDom渲染实际DOM,VDOM -> DOM

理解好这一步,我们再看ReactDOM。React将jsx转换为“虚拟dom”对象。我们再利用ReactDom的虚拟dom通过render函数,转换成dom。再通过插入到我们的真是页面中。

这就是整个mini react的一个简述过程。

手写react过程

1)基本架子的搭建

react的功能化问题,暂时不考虑。例如,启动react,怎么去识别JSX,实现热更新服务等等,我们的重点在于react自身。我们借用一下一下react-scripts插件。

有几种种方式创建我们的基本架子:

  • 利用 create-react-app zwz_react_origin快速搭建,然后删除原本的react,react-dom等文件。(zwz_react_origin是我的项目名称)

  • 第二种,复制下边代码。新建package.json

      {
        "name": "zwz_react_origin",
        "scripts": {
          "start": "react-scripts start"
        },
        "version": "0.1.0",
        "private": true,
        "dependencies": {
          "react-scripts": "3.4.1"
        },
      }
    
    

    然后新建public下边的index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
        </head>
        <body>
          <div id="root"></div>
        </body>
      </html>
    
    

    再新建src下边的index.js

    这时候react-scripts会快速的帮我们定为到index.html以及引入index.js

      import React from "react";
      import ReactDOM from "react-dom";
    
      let jsx = (
        <div>
          <div className="">react启动成功</div>
        </div>
      );
      ReactDOM.render(jsx, document.getElementById("root"));
    
    

    这样,一个可以写react源码的轮子就出来了。

2) React的源码

let obj = (
  <div>
    <div className="class_0">你好</div>
  </div>
);
console.log(`obj=${ JSON.stringify( obj) }`);

首先,我们上述代码,如果我们不import React处理的话,我们可以打印出:
‘React’ must be in scope when using JSX react/react-in-jsx-scope
是的,编译不下去,因为js文件再react-script,他已经识别到obj是jsx。该jsx却不能解析成虚拟dom, 此时我们的页面就会报错。通过资料的查阅,或者是源码的跟踪,我们可以知道,实际上,识别到jsx之后,会调用页面中的createElement转换为虚拟dom。

我们import React,看看打印出来什么?

+ import React from "react";
let obj = (
  <div>
    <div className="class_0">你好</div>
  </div>
);
console.log(`obj:${
      JSON.stringify( obj) }`);

结果:
jsx={
   "type":"div","key":null,"ref":null,"props":{
   "children":{
   "type":"div","key":null,"ref":null,"props":{
   "className":"class_0","children":"你好"},"_owner":null,"_store":{
   }}},"_owner":null,"_store":{
   }}

由上边结论可以知道, babel会识别到我们的jsx,通过createElement并将其dom(html语法)转换为虚拟dom。从上述的过程,我们可以看到虚拟dom的组成,由type,key,ref,props组成。我们来模拟react的源码。

此时我们已经知道react中的createElement的作用是什么,我们可以尝试着自己来写一个createElement(新建react.js引入并手写下边代码):

function createElement() {
   
  console.log("createElement", arguments);
}

export default {
   
  createElement,
};

此时的打印结果:



我们可以看出对象传递的时候,dom的格式,先传入type, 然后props属性,我们根据原本react模拟一下这个对象转换的打印:

function createElement(type, props, ...children) {
   
  props.children = children;
  return {
   
    type,
    props,
  };
}

这样,我们已经把最简版的一个react实现,我们下边继续看看如何render到页面

3) ReactDom.render

import React from "react";
+ import ReactDOM from "react-dom";
let jsx = (
  <div>
    <div className="class_0">你好</div>
  </div>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值