React 引入import React 原理
本质上来说JSX是React.createElement(component, props, ...children)方法的语法糖。
所以我们如果使用了JSX,我们其实就是在使用React,所以我们就需要引入React
前言
React是前端最受欢迎的框架之一,解读其源码的文章非常多,但是我想从另一个角度去解读React:从零开始实现一个React,从API层面实现React的大部分功能,在这个过程中去探索为什么有虚拟DOM、diff、为什么setState这样设计等问题。
提起React,总是免不了和Vue做一番对比
Vue的API设计非常简洁,但是其实现方式却让人感觉是“魔法”,开发者虽然能马上上手,但其原理却很难说清楚。
相比之下React的设计哲学非常简单,虽然有很多需要自己处理的细节问题,但它没有引入任何新的概念,相对更加的干净和简单。
关于jsx
在开始之前,我们有必要搞清楚一些概念。
我们来看一下这样一段代码:
const title = <h1 className="title">Hello, world!</h1>;
这段代码并不是合法的js代码,它是一种被称为jsx的语法扩展,通过它我们就可以很方便的在js代码中书写html片段。
本质上,jsx是语法糖,上面这段代码会被babel转换成如下代码:
const title = React.createElement(
'h1',
{ className: 'title' },
'Hello, world!'
);
React.createElement和虚拟DOM
前文提到,jsx片段会被转译成用React.createElement方法包裹的代码。所以第一步,我们来实现这个React.createElement方法
从jsx转译结果来看,createElement方法的参数是这样:
createElement( tag, attrs, child1, child2, child3 );
第一个参数是DOM节点的标签名,它的值可能是div,h1,span等等
第二个参数是一个对象,里面包含了所有的属性,可能包含了className,id等等
从第三个参数开始,就是它的子节点
我们对createElement的实现非常简单,只需要返回一个对象来保存它的信息就行了。
function createElement( tag, attrs, ...children ) {
return {
tag,
attrs,
children
}
}
函数的参数 ...children使用了ES6的rest参数,它的作用是将后面child1,child2等参数合并成一个数组children。
现在我们来试试调用它
// 将上文定义的createElement方法放到对象React中
const React = {
createElement
}
const element = (
<div>
hello<span>world!</span>
</div>
);
console.log( element );
打开调试工具,我们可以看到输出的对象和我们预想的一致
我们的createElement方法返回的对象记录了这个DOM节点所有的信息,换言之,通过它我们就可以生成真正的DOM,这个记录信息的对象我们称之为虚拟DOM。
ReactDOM.render
接下来是ReactDOM.render方法,我们再来看这段代码
ReactDOM.render(
<h1>Hello, world!</h1>
document.getElementById('root')
);
以上经过转换,这段代码变成了这样
ReactDOM.render(
React.createElement( 'h1', null, 'Hello, world!' ),
document.getElementById('root')
)
```
所以render的第一个参数实际上接受的是createElement返回的对象,也就是虚拟DOM
而第二个参数则是挂载的目标DOM
总而言之,render方法的作用就是将虚拟DOM渲染成真实的DOM,下面是它的实现:
```function setAttribute( dom, name, value ) {
// 如果属性名是className,则改回class
if ( name === 'className' ) name = 'class';
// 如果属性名是onXXX,则是一个事件监听方法
if ( /on\w+/.test( name ) ) {
name = name.toLowerCase();
dom[ name ] = value || '';
// 如果属性名是style,则更新style对象
} else if ( name === 'style' ) {
if ( !value || typeof value === 'string' ) {
dom.style.cssText = value || '';
} else if ( value && typeof value === 'object' ) {
for ( let name in value ) {
// 可以通过style={ width: 20 }这种形式来设置样式,可以省略掉单位px
dom.style[ name ] = typeof value[ name ] === 'number' ? value[ name ] + 'px' : value[ name ];
}
}
// 普通属性则直接更新属性
} else {
if ( name in dom ) {
dom[ name ] = value || '';
}
if ( value ) {
dom.setAttribute( name, value );
} else {
dom.removeAttribute( name );
}
}
}
这里其实还有个小问题:当多次调用render函数时,不会清除原来的内容。所以我们将其附加到ReactDOM对象上时,先清除一下挂载目标DOM的内容:
const ReactDOM = {
render: ( vnode, container ) => {
container.innerHTML = '';
return render( vnode, container );
}
}
渲染和更新
到这里我们已经实现了React最为基础的功能,可以用它来做一些事了。
我们先在index.html中添加一个根节点
我们先来试试官方文档中的Hello,World
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('root')
);```
运行以后 效果基本就出来了
React 引入import React 原理的更多相关文章
- 为什么import React from 'react',React首字母必须大写?
很奇怪的是,明明没有用到 React,但是我不得不 import React.这是为什么? import React from 'react'; export default function (pr ...
- react实战系列 —— React 中的表单和路由的原理
其他章节请看: react实战 系列 React 中的表单和路由的原理 React 中的表单是否简单好用,受控组件和非受控是指什么? React 中的路由原理是什么,如何更好的理解 React 应用的 ...
- 10分钟了解 react 引入的 Hooks
"大家好,我是谷阿莫,今天要将的是一个...",哈哈哈,看到这个题我就想到这个开头.最近react 官方在 2018 ReactConf 大会上宣布 React v16.7.0-a ...
- 深入理解React:事件机制原理
目录 序言 DOM事件流 事件捕获阶段.处于目标阶段.事件冒泡阶段 addEventListener 方法 React 事件概述 事件注册 document 上注册 回调函数存储 事件分发 小结 参考 ...
- React Native 入门到原理(详解)
抛砖引玉(帮你更好的去理解怎么产生的 能做什么) 砖一.动态配置 由于 AppStore 审核周期的限制,如何动态的更改 app 成为了永恒的话题.无论采用何种方式,我们的流程总是可以归结为以下三部曲 ...
- React动态import()
React动态import() react-router@v4代码分离,推荐的import().这里分享webpack配置和使用方法. 首先安装两个必须的包 cnpm i react-loadable ...
- [React] Create and import React components with Markdown using MDXC
In this lesson I demonstrate how to use the library MDXC to create and import React components with ...
- React引入,运行
1.引入 <script src="https://cdn.bootcss.com/react/15.5.4/react.min.js"></script> ...
- react引入ggEditor流程图
遇到的问题 1.propsAPI获取不到内容:withPropsAPI包裹的组件必须是GGEditor的子组件. 2.自定义组件如何使用:正确的办法是通过config配置,参照上面的代码(之前我在在内 ...
随机推荐
- 【mysql】新增列 时间戳
参考地址:https://www.cnblogs.com/SZxiaochun/p/9299392.html ALTER TABLE worksheet_data_12 ), ADD COLUMN ` ...
- Linux学习笔记之Linux磁盘及文件系统管理笔记
Linux磁盘及文件系统管理 CPU,memory(RAM),I/O i/o: disks,ehtercard disks:持久存储数据 接口类型: IDE(ata): 并口,133MB/s;并行总线 ...
- wangeditor视频
wangeditor网址http://www.wangeditor.com/ 目前使用的是3.11版本 使用步骤 1.引用wangEditor.min.js 2.代码 2.1 取得函数var E = ...
- php调用webservice接口,java代码接收不到参数
前段时间做了一个项目的二次开发,有个功能是需要php调用java实现的webservice接口,并传递一些参数给接口,然后按照对方提供的接口说明文档进行传参调用,java那边有接收到请求,但是参数总是 ...
- Java自学-面向对象 方法
Java类的方法 在LOL中,一个英雄可以做很多事情,比如超神,超鬼,坑队友 能做什么在类里面就叫做方法 示例 1 : 什么是方法 比如队友残血正在逃跑,你过去把路给别人挡住了,导致他被杀掉. 这就是 ...
- drf--ModelSerializers序列化
目录 drf--ModelSerializers序列化 项目准备 配置 settings.py 路由 多表设计 表关系分析 创建models 模型序列化 自定义模型序列化 api/serializer ...
- tomcat重启session不失效问题
本地写代码每次重启都要重新登录浪费了很多时间,如何重启不用重新登录呢,只要让tomcat在关闭时将session写入文件中,在启动时从文件中读取session即可. 只需在conf/context.x ...
- 2019-08-01 JQuery事件
Jquery简单的事件 l blur(fn) 当失去焦点时 l change(fn) 当内容发生改变时 l click(fn) 当鼠标单击时 l dblclick 当鼠标双击时 l focus(fn) ...
- ReactiveObjC basic
基础-> https://www.jianshu.com/p/cd4031fbf8ff 在RAC中,万物皆信号. RAC 指的就是 RactiveCocoa ,是 Github 的一个开源框架, ...
- toString()和Object.prototype.toString.call() 不一样
var arr=[1,2,3];arr.toString()//输出“1,2,3”Object.prototype.toString.call(arr)//输出 "[object Array ...