JSX是React框架背后的核心机理,它使得我们可以在Javaascript中直接书写html。
本文将由JSX展开实现一个简化版的simpleReact。
init
1 | $ npm init -y // 初始化当前项目 |
webpack
webpack 是一个前端打包工具,支持各种自定义loader,plugin。
使用方法详见 webpack 基础用法
babel
babel 是一个将高版本的js,编译成老版本Js的一种工具。
babel在webpack中是以loader的形式存在的。
babel本身是一个不带任何配置的一个核心,@babel/preset-env
是一个配置好了的、比较常见的(如es6 -> es5)转换配置包
1 | $ npm i @babel/core @babel/preset-env babel-loader -D |
编写webpack 配置文件
1 | // webpack.config.js |
@babel/plugin-transform-react-jsx
在常规的babel preset配置中是不包含JSX的转换的,所以需要借助单独的插件
1 | $ npm i @babel/plugin-transform-react-jsx -D |
修改webpack配置
1 | // webpack.conf.js |
书写
当在js中书写jsx语法,使用webpack打包之后的内容如下:
1 | // main.js |
这是由于babel-jsx翻译之后生成的js为React.createElement(ele)
函数,而React.createElement
在当前是一个未定义的状态。
@babel/plugin-transform-react-jsx 扩展
@babel/plugin-transform-react-jsx
支持传入的第二个参数为当前的函数名,如React.createElement
。
修改webpack.conf.js
1 | plugins: [ |
再使用webpack打包jsx转换之后:
1 | var x = wgwCreateElement("div", null); |
即函数名变为了自定义的函数名。
编写自定义函数
1 | window.a = <div class="class" id="id" > |
JSX组件机制
在jsx中,如果tagName 为小写,那么就会认为是一个原生的html标签,如果是大写开头,那么就会认为是一个组件。
如改写main.js
1 | window.a = <MyComponent class="class" id="id" > |
编写MyComponent
代码不想赘述了,详见 github main.js
toy-react.js
补充
jsx编译方式
运行时编译(React Automatic Runtime)
当pagram参数值为wgwCreateElement,所以代码编译时会自动解析jsx并调用wgwCreateElement方法。所以定义了pagram之后函数不需要去调用
手动引入 (React Classic Runtime)
为什么render方法里父节点要接收一个component.root作为参数而不是component?
在运行编jsx译时,调用wgwCreateElement方法后会实例化一个Component对象,该对象初始root为null,从而会调用render方法(即MyComponent中的render方法),该方法返回一个JSX,从而又会调用createElement方法,此时是一个真实的DOM节点,所以会初始化一个ElementWrapper对象,该对象包含一个root属性,这时root就不为null了,而是一个div。