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() 的时候, 其内部 ...
随机推荐
- C++解析(26):函数模板与类模板
0.目录 1.函数模板 1.1 函数模板与泛型编程 1.2 多参数函数模板 1.3 函数重载遇上函数模板 2.类模板 2.1 类模板 2.2 多参数类模板与特化 2.3 特化的深度分析 3.小结 1. ...
- debug - taotao项目 - IDEA拖动文件的自动重命名是超级巨坑, 一定要非常小心
大量的如下错误: org.springframework.beans.factory.BeanCreationException: Could not autowire field 还是要相信报错 不 ...
- c# 字符串转Byte[],如何将Byte[]插入到Oracle Blob
byte[] xx=Encoding.Default.GetBytes("12121232"); 插入数据库 string sqlStr = "update sys_ta ...
- HDU4625 JZPTREE——第二类斯特林数
复杂度大概O(nk) 一些尝试:1.对每个点推出1,2,3,,,到k次方的值.但是临项递推二项式展开也要考虑到具体每个点的dist 2.相邻k次方递推呢?递推还是不能避免k次方的展开 k次方比较讨厌, ...
- Web前端之HTML详解20180327
一.html概述 html就是超文本标记语言的简写,是最基础的网页语言.html通过标签来定义语言,代码都是由标签所组成. 1.html代码从<html>开始</html>结束 ...
- Codeforces 932.E Team Work
E. Team Work time limit per test 2 seconds memory limit per test 256 megabytes input standard input ...
- update condition 字段报错
mysql> update tf_user_present set condition="0" where id=1;ERROR 1064 (42000): You have ...
- 微信小程序,页面分享
onShareAppMessage: function () { return { title: '微信小程序联盟', desc: '最具人气的小程序开发联盟!', path: '/page/user ...
- SpringBoot(三) :Spring boot 中 Redis 的使用
前言: 这一篇讲的是Spring Boot中Redis的运用,之前没有在项目中用过Redis,所以没有太大的感觉,以后可能需要回头再来仔细看看. 原文出处: 纯洁的微笑 SpringBoot对常用的数 ...
- 巧用Java中Calendar工具类
Java的JDK中提供了一系列好用的util工具类.Calendar就是java.util中用于处理日期的工具类.且该工具类易学易用实用. 工具类Calendar是抽象类. PS:为什么把Calend ...