〇、看前准备

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 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?的更多相关文章

  1. React 16 源码瞎几把解读 【二】 react组件的解析过程

    一.一个真正的react组件编译后长啥样? 我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构.一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周 ...

  2. React 16 源码瞎几把解读 【三 点 一】 把react组件对象弄到dom中去(矛头指向fiber,fiber不解读这个过程也不知道)

    一.ReactDOM.render 都干啥了 我们在写react的时候,最后一步肯定是 ReactDOM.render( <div> <Home name="home&qu ...

  3. React 16 源码瞎几把解读 【一】 从jsx到一个react 虚拟dom对象

    一.jsx变createElement 每一个用jsx语法书写的react组件最后都会变成 react.createElement(...)这一坨东西, // 转变前 export default ( ...

  4. React 16 源码瞎几把解读 【三 点 二】 react中的fiberRoot

    〇.先来看看常用的常量 NoWork = 0 noTimeout = undefined HostRoot = 3 NoContext = 0b000; AsyncMode = 0b001; Stri ...

  5. React Fiber源码分析 (介绍)

    写了分析源码的文章后, 总觉得缺少了什么, 在这里补一个整体的总结,输出个人的理解~ 文章的系列标题为Fiber源码分析, 那么什么是Fiber,官方给出的解释是: React Fiber是对核心算法 ...

  6. 《React Native 精解与实战》书籍连载「React Native 源码学习方法及其他资源」

    此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React Native 源码学习方法及其他资源. 最后的章节给大家介绍 React Native ...

  7. React的React.createContext()源码解析(四)

    一.产生context原因 从父组件直接传值到孙子组件,而不必一层一层的通过props进行传值,相比较以前的那种传值更加的方便.简介. 二.context的两种实现方式 1.老版本(React16.x ...

  8. React的React.createElement源码解析(一)

    一.什么是jsx  jsx是语法糖  它是js和html的组合使用  二.为什么用jsx语法 高效定义模版,编译后使用 不会带来性能问题 三.jsx语法转化为js语法  jsx语法通过babel转化为 ...

  9. vue 源码详解(二): 组件生命周期初始化、事件系统初始化

    vue 源码详解(二): 组件生命周期初始化.事件系统初始化 上一篇文章 生成 Vue 实例前的准备工作 讲解了实例化前的准备工作, 接下来我们继续看, 我们调用 new Vue() 的时候, 其内部 ...

随机推荐

  1. ZOJ2686_Cycle Gameu

    题目的意思是给你一个多边形,每条边上有一个权值,你开始在第一个点.每次你必须经过一条有权值的边,并且把该边的权值减小到任意一个非负值,到达该边的另外一个点. 谁第一个无法操作就算输. 题意很简单,解法 ...

  2. 【刷题】BZOJ 1036 [ZJOI2008]树的统计Count

    Description 一棵树上有n个节点,编号分别为1到n,每个节点都有一个权值w.我们将以下面的形式来要求你对这棵树完成 一些操作: I. CHANGE u t : 把结点u的权值改为t II. ...

  3. 【刷题】洛谷 P3806【模板】点分治1

    题目背景 感谢hzwer的点分治互测. 题目描述 给定一棵有n个点的树 询问树上距离为k的点对是否存在. 输入输出格式 输入格式: n,m 接下来n-1条边a,b,c描述a到b有一条长度为c的路径 接 ...

  4. [AT2148] [arc063_c] Integers on a Tree

    题目链接 AtCoder:https://arc063.contest.atcoder.jp/tasks/arc063_c 洛谷:https://www.luogu.org/problemnew/sh ...

  5. 连接Mysql数据库

    JDBC连接数据库 创建一个以JDBC连接数据库的程序,包含7个步骤: 1.加载JDBC驱动程序: 在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机), 这通过java.la ...

  6. 《Linux内核设计与实现》学习总结 Chap1~2

    第一章 Linux内核简介 一.历史 由于Unix系统设计简洁并且在发布时提供源代码,所以许多其他组织和团体都对它进了进一步的开发. Unⅸ虽然已经使用了40年,但计算机科学家仍然认为它是现存操作系统 ...

  7. 解题:APIO 2008 免费道路

    题面 我们发现我们可以很容易知道最终完成的生成树中有多少鹅卵石路,但是我们不好得到这棵生成树的结构,所以我们尽量“谨慎”地完成生成树·,最好是一点点加到我们要达到的标准而不是通过删掉一些东西来完成 我 ...

  8. python基础----函数的定义和调用、return语句、变量作用域、传参、函数嵌套、函数对象、闭包、递归函数

    1.函数的定义: 函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段. 函数能提高应用的模块性,和代码的重复利用率.你已经知道Python提供了许多内建函数,比如print().但你也可 ...

  9. socket编程学习step2

    引言:主机之间如何相互交互呢?网络层的“ip地址”可以唯一标识网络中的主机,而传输层的“协议+端口“可以唯一标识主机中的应用进程.这样利用三元组(ip地址,协议,端口)就可以标识网络的进程了,网络中的 ...

  10. portal商品展示功能逻辑

    看下接口: 返回值: 门户商品搜索功能的实现: 根据分类id进行搜索,根据关键词进行搜索,并按照一定的顺序排序 业务逻辑: 1.查询分类是否存在. 2.如果分类存在,则递归分类,展示父类商品,子类商品 ...