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() 的时候, 其内部 ...
随机推荐
- 【EF】EF Code-First数据迁移
Code-First数据迁移 首先要通过NuGet将EF升级至最新版本. 新建MVC 4项目MvcMigrationDemo 添加数据模型 Person 和 Department,定义如下: usi ...
- HDU 4758——Walk Through Squares——2013 ACM/ICPC Asia Regional Nanjing Online
与其说这是一次重温AC自动机+dp,倒不如说这是个坑,而且把队友给深坑了. 这个题目都没A得出来,我只觉得我以前的AC自动机的题目都白刷了——深坑啊. 题目的意思是给你两个串,每个串只含有R或者D,要 ...
- BZOJ 1975 魔法猪学院(A*求K短路)
显然每次贪心的走最少消耗的路径即可.那么也就是找出最短路,次短路,,,K短路之后消耗E的能量的最多的路径条数. 也就是裸的A*算法. #include <bits/stdc++.h> us ...
- C++解析(22):父子间的冲突
0.目录 1.同名覆盖 2.赋值兼容 3.函数重写遇上赋值兼容 4.小结 1.同名覆盖 子类中是否可以定义父类中的同名成员?如果可以,如何区分?如果不可以,为什么? 父子间的冲突: 子类可以定义父类中 ...
- [洛谷P5190][COCI 2010] PROGRAM
题目大意:给你$k(k\leqslant10^6)$个数,$f(x)$表示$x$的约数在$k$个数中出现的次数,在这任何数都是$0$的约数.$m(m\leqslant10^6)$次询问,每次给出$l, ...
- BZOJ2212 [Poi2011]Tree Rotations 【线段树合并】
题目链接 BZOJ2212 题解 一棵子树内的顺序不影响其与其它子树合并时的答案,这一点与归并排序的思想非常相似 所以我们只需单独处理每个节点的两棵子树所产生的最少逆序对即可 只有两种情况,要么正序要 ...
- 电子商务(电销)平台中财务模块(Finance)数据库设计明细
以下是自己在电子商务系统设计中的数据库设计经验总结,而今发表出来一起分享,如有不当,欢迎跟帖讨论~ 资金账户表 (finance_account)|-- 自动编号|-- 用户编号|-- 预付款 (ad ...
- 【loj2064】找相同字符
Portal --> loj2064 Solution 这里是用后缀数组做的版本!(晚点再用Sam写一遍qwq) 首先一个字符串的子串其实就是这个字符串某个后缀的前缀,所以我们有一个十分简单 ...
- pycrypto 安装
https://www.dlitz.net/software/pycrypto/ 下载pycrypto-2.6.1.tar.gz,解压后 python setup.py build python se ...
- 简单shell 编程
简单shell编程 by dreamboy #!/bin/bash while true do echo clear echo echo " 系统维护菜单 " echo &qu ...