React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?
〇、看前准备
1.自行clone react最新代码
2.自行搭建一个能跑react的test项目
一、看表面:那些插件 如何解析JSX
有如下一段代码:
- // ---- hearder.jsx 组件
- import React,{Component} from 'react';
- export default (props)=>(
- <h1 ref="h1">我是header.{props.kk}</h1>
- );
- // ---- Home.jsx 页面级组件
- import React,{Component} from 'react';
- import Header from '../components/header';
- class Home extends Component {
- constructor(props){
- super(props);
- }
- componentWillMount(){
- console.log('willMount');
- }
- render(){
- let {name} = this.props;
- console.log(this);
- return (
- <div ref="home">
- <Header kk="jsx"/>
- <div>主页</div>
- <div>
- <p>哈哈哈哈</p>
- </div>
- </div>
- )
- }
- }
- export default Home;
- // React入口文件 app.js
- import ReactDOM from 'react-dom';
- import React from 'react';
- import Home from './page/home';
- let abc = ReactDOM.render(
- <div>
- <Home name="home"/>
- </div>
- ,
- document.getElementById('app')
- );
发现每一个出现jsx语法的地方都要出现import React from 'react';
其实react 的引入就是为了将解析完的jsx 能有createElement方法被执行,在浏览器里打开控制台,我们发现代码被整成了这个样子:
- // ----header.jsx
- var _default = function _default(props) {
- return _react2.default.createElement(
- "h1",
- { ref: "h1" },
- "\u6211\u662Fheader.",
- props.kk
- );
- };
- exports.default = _default;
- // home.jsx
- var Home = function (_Component) {
- _inherits(Home, _Component);
- function Home(props) {
- _classCallCheck(this, Home);
- return _possibleConstructorReturn(this, (Home.__proto__ || Object.getPrototypeOf(Home)).call(this, props));
- }
- _createClass(Home, [{
- key: 'componentWillMount',
- value: function componentWillMount() {
- console.log('willMount');
- }
- }, {
- key: 'render',
- value: function render() {
- var name = this.props.name;
- console.log(this);
- return _react2.default.createElement(
- 'div',
- { ref: 'home' },
- _react2.default.createElement(_header2.default, { kk: 'js' }),
- _react2.default.createElement(
- 'div',
- null,
- '\u4E3B\u9875'
- ),
- _react2.default.createElement(
- 'div',
- null,
- _react2.default.createElement(
- 'p',
- null,
- '\u54C8\u54C8\u54C8\u54C8'
- )
- )
- );
- }
- }, {
- key: '__reactstandin__regenerateByEval',
- // @ts-ignore
- value: function __reactstandin__regenerateByEval(key, code) {
- // @ts-ignore
- this[key] = eval(code);
- }
- }]);
- return Home;
- }(_react.Component);
- var _default = Home;
- exports.default = _default;
- // app.js
- _reactDom2.default.render(_react2.default.createElement(
- 'div',
- null,
- _react2.default.createElement(_home2.default, { name: 'home' })
- ), document.getElementById('app'));
二、为啥外面非得包一个
我们知道我们在写react的时候,不管你用的是webpack也好还是fis3 、gulp 或者直接撸js+html,都需要引入jsx语法转义插件,这些插件把jsx语法的字符转变成了我们在浏览器看到的样子。
每个组件都有render方法,每个render方法都会return一个React.createElement 执行后的东西
我将header.jsx改为
- export default (props)=>(
- <h1 ref="h1">我是header.{props.kk}</h1>
- <p>hahaha</p>
- );
当我们在jsx中写若干个标签而外面不包东西的话,以babel-loader为例,丫会提示:
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag
我们通过追溯得到jsx语法的解析其实是在 baabel-core/node_modules/babylon/index.js 中解析的
我们注释掉出现的报错信息,因能力有限水平一般且对babylon有任何了解,所以只通过粗浅的改动以下代码让webpack能够编译通过(当然js语法肯定是不成功的)
- Tokenizer.prototype.readRegexp = function readRegexp() {
- ......
- for (;;) {
- // if (this.state.pos >= this.input.length) this.raise(start, "Unterminated regular expression");
- var ch = this.input.charAt(this.state.pos);
- if (lineBreak.test(ch)) {
- // this.raise(start, "Unterminated regular expression");
- break; // 增加一个break
- }
- ..............
- return this.finishToken(types.regexp, {
- pattern: content,
- flags: mods
- });
- };
- pp$9.jsxParseElementAt = function (startPos, startLoc) {
- ............
- // if (this.match(types.relational) && this.state.value === "<") {
- // this.raise(this.state.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
- // }
- return this.finishNode(node, "JSXElement");
- };
编译出来的代码结构如下:
- var _default = function _default(props) {
- return _react2.default.createElement(
- "h1",
- { ref: "h1" },
- "\u6211\u662Fheader.",
- props.kk
- ) < p > hahaha < /p>/;
- };
- exports.default = _default;
可见babylon在解析jsx的时候会默认将第一个闭合标签 return 出去,就算第二个咱们改babylon改的再成功能正确解析p标签这个jsx,岂不是return 两个东西出去了,函数里怎么可能有两个return呢!
所以react的所有组件必须放在一个闭合标签里(当然了16 版本也可以是一个数组,不用放在闭合标签里,以后再说)。
看到
SyntaxError: Adjacent JSX elements must be wrapped in an enclosing tag
和
SyntaxError: Unterminated regular expression
的报错
一定要检查自己的jsx是否在一个闭合标签中,同时是否语法正确
React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?的更多相关文章
- React 16 源码瞎几把解读 【二】 react组件的解析过程
一.一个真正的react组件编译后长啥样? 我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构.一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周 ...
- React 16 源码瞎几把解读 【三 点 一】 把react组件对象弄到dom中去(矛头指向fiber,fiber不解读这个过程也不知道)
一.ReactDOM.render 都干啥了 我们在写react的时候,最后一步肯定是 ReactDOM.render( <div> <Home name="home&qu ...
- React 16 源码瞎几把解读 【一】 从jsx到一个react 虚拟dom对象
一.jsx变createElement 每一个用jsx语法书写的react组件最后都会变成 react.createElement(...)这一坨东西, // 转变前 export default ( ...
- React 16 源码瞎几把解读 【三 点 二】 react中的fiberRoot
〇.先来看看常用的常量 NoWork = 0 noTimeout = undefined HostRoot = 3 NoContext = 0b000; AsyncMode = 0b001; Stri ...
- React Fiber源码分析 (介绍)
写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...
- 《React Native 精解与实战》书籍连载「React Native 源码学习方法及其他资源」
此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源. 最后的章节给大家介绍 React Native ...
- React的React.createContext()源码解析(四)
一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...
- React的React.createElement源码解析(一)
一.什么是jsx jsx是语法糖 它是js和html的组合使用 二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法 jsx语法通过babel转化为 ...
- vue 源码详解(二): 组件生命周期初始化、事件系统初始化
vue 源码详解(二): 组件生命周期初始化.事件系统初始化 上一篇文章 生成 Vue 实例前的准备工作 讲解了实例化前的准备工作, 接下来我们继续看, 我们调用 new Vue() 的时候, 其内部 ...
随机推荐
- list+map
通常读取数据库表中的一条记录后,可以存储于Hashmap变量中:若要读取多条记录,则依次读取每个记录时,先用Hashmap变量存取,然后将Hashmap加到ArrayList变量中. 注意: 每次读取 ...
- Qt5 UI信号、槽自动连接的控件重名
Qt5 UI信号.槽自动连接的控件重名 来源 http://blog.csdn.net/goldenhawking/article/details/51865909 对Qt5稍有熟悉的童鞋都知道信号. ...
- 【题解】CF#713 E-Sonya Partymaker
这题真的想了挺久的,然而到最后也还是没想到怎样处理环的情况……网上竟然也完全没有题解,无奈之下到 CF 的 AC 代码里面去找了一份膜拜了一下.感谢~ 由于觉得这题有一定的难度,自己看代码也看了比较久 ...
- Visual Format Language(VFL)视图约束
约束(Constraint)在IOS编程中非常重要,这关乎到用户的直接体验问题. IOS中视图约束有几种方式,常见的是在IB中通过Pin的方式手动添加约束,菜单Editor->Pin->. ...
- Zabbix3.4.5部署安装(二)
一.部署环境 一)系统环境: [root@Node3 ~]# cat /etc/redhat-release //查看系统版本 CentOS Linux release (Core) [root@No ...
- winform登录代码
Program.cs文件中 static class Program { /// <summary> /// 应用程序的主入口点. /// </summary> [STAThr ...
- jsonP 后台写法 及 层级树型数据递归查询
Controller层: package com.taotao.rest.controller; import org.springframework.beans.factory.annotation ...
- Libevent学习笔记(四) bufferevent 的 concepts and basics
Bufferevents and evbuffers Every bufferevent has an input buffer and an output buffer. These are of ...
- 金牌架构师:我们是这样设计APP数据统计产品的
前言:近期,智能大数据服务商“个推”推出了应用统计产品“个数”,今天我们就和大家来谈一谈个数实时统计与AI数据智能平台整合架构设计. 很多人可能好奇,拥有数百亿SDK的个推,专注消息推送服务多年,现在 ...
- duilib 给List表头增加百分比控制宽度的功能
转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42503147 最近项目里需要用到包含表头列表,而窗体大小改变后,每个列表 ...