〇、看前准备

1.自行clone react最新代码

2.自行搭建一个能跑react的test项目

一、看表面:那些插件 如何解析JSX

有如下一段代码:

  1. // ---- hearder.jsx 组件
  2. import React,{Component} from 'react';
  3.  
  4. export default (props)=>(
  5. <h1 ref="h1">我是header.{props.kk}</h1>
  6. );
  7.  
  8. // ---- Home.jsx 页面级组件
  9. import React,{Component} from 'react';
  10. import Header from '../components/header';
  11. class Home extends Component {
  12. constructor(props){
  13. super(props);
  14. }
  15. componentWillMount(){
  16. console.log('willMount');
  17. }
  18. render(){
  19. let {name} = this.props;
  20. console.log(this);
  21. return (
  22. <div ref="home">
  23. <Header kk="jsx"/>
  24. <div>主页</div>
  25. <div>
  26. <p>哈哈哈哈</p>
  27. </div>
  28. </div>
  29. )
  30. }
  31. }
  32.  
  33. export default Home;
  34.  
  35. // React入口文件 app.js
  36.  
  37. import ReactDOM from 'react-dom';
  38. import React from 'react';
  39. import Home from './page/home';
  40. let abc = ReactDOM.render(
  41. <div>
  42. <Home name="home"/>
  43. </div>
  44. ,
  45. document.getElementById('app')
  46. );

发现每一个出现jsx语法的地方都要出现import React from 'react';

其实react 的引入就是为了将解析完的jsx 能有createElement方法被执行,在浏览器里打开控制台,我们发现代码被整成了这个样子:

  1. // ----header.jsx
  2.  
  3. var _default = function _default(props) {
  4. return _react2.default.createElement(
  5. "h1",
  6. { ref: "h1" },
  7. "\u6211\u662Fheader.",
  8. props.kk
  9. );
  10. };
  11.  
  12. exports.default = _default;
  13.  
  14. // home.jsx
  15.  
  16. var Home = function (_Component) {
  17. _inherits(Home, _Component);
  18.  
  19. function Home(props) {
  20. _classCallCheck(this, Home);
  21.  
  22. return _possibleConstructorReturn(this, (Home.__proto__ || Object.getPrototypeOf(Home)).call(this, props));
  23. }
  24.  
  25. _createClass(Home, [{
  26. key: 'componentWillMount',
  27. value: function componentWillMount() {
  28. console.log('willMount');
  29. }
  30. }, {
  31. key: 'render',
  32. value: function render() {
  33. var name = this.props.name;
  34.  
  35. console.log(this);
  36. return _react2.default.createElement(
  37. 'div',
  38. { ref: 'home' },
  39. _react2.default.createElement(_header2.default, { kk: 'js' }),
  40. _react2.default.createElement(
  41. 'div',
  42. null,
  43. '\u4E3B\u9875'
  44. ),
  45. _react2.default.createElement(
  46. 'div',
  47. null,
  48. _react2.default.createElement(
  49. 'p',
  50. null,
  51. '\u54C8\u54C8\u54C8\u54C8'
  52. )
  53. )
  54. );
  55. }
  56. }, {
  57. key: '__reactstandin__regenerateByEval',
  58. // @ts-ignore
  59. value: function __reactstandin__regenerateByEval(key, code) {
  60. // @ts-ignore
  61. this[key] = eval(code);
  62. }
  63. }]);
  64.  
  65. return Home;
  66. }(_react.Component);
  67.  
  68. var _default = Home;
  69. exports.default = _default;
  70.  
  71. // app.js
  72.  
  73. _reactDom2.default.render(_react2.default.createElement(
  74. 'div',
  75. null,
  76. _react2.default.createElement(_home2.default, { name: 'home' })
  77. ), document.getElementById('app'));

二、为啥外面非得包一个

我们知道我们在写react的时候,不管你用的是webpack也好还是fis3 、gulp 或者直接撸js+html,都需要引入jsx语法转义插件,这些插件把jsx语法的字符转变成了我们在浏览器看到的样子。

每个组件都有render方法,每个render方法都会return一个React.createElement 执行后的东西

我将header.jsx改为

  1. export default (props)=>(
  2. <h1 ref="h1">我是header.{props.kk}</h1>
  3. <p>hahaha</p>
  4. );

当我们在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语法肯定是不成功的)

  1. Tokenizer.prototype.readRegexp = function readRegexp() {
  2. ......
  3. for (;;) {
  4. // if (this.state.pos >= this.input.length) this.raise(start, "Unterminated regular expression");
  5. var ch = this.input.charAt(this.state.pos);
  6. if (lineBreak.test(ch)) {
  7. // this.raise(start, "Unterminated regular expression");
  8. break; // 增加一个break
  9. }
  10. ..............
  11. return this.finishToken(types.regexp, {
  12. pattern: content,
  13. flags: mods
  14. });
  15. };
  16.  
  17. pp$9.jsxParseElementAt = function (startPos, startLoc) {
  18. ............
  19. // if (this.match(types.relational) && this.state.value === "<") {
  20. // this.raise(this.state.start, "Adjacent JSX elements must be wrapped in an enclosing tag");
  21. // }
  22. return this.finishNode(node, "JSXElement");
  23. };

编译出来的代码结构如下:

  1. var _default = function _default(props) {
  2. return _react2.default.createElement(
  3. "h1",
  4. { ref: "h1" },
  5. "\u6211\u662Fheader.",
  6. props.kk
  7. ) < p > hahaha < /p>/;
  8. };
  9.  
  10. 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. list+map

    通常读取数据库表中的一条记录后,可以存储于Hashmap变量中:若要读取多条记录,则依次读取每个记录时,先用Hashmap变量存取,然后将Hashmap加到ArrayList变量中. 注意: 每次读取 ...

  2. Qt5 UI信号、槽自动连接的控件重名

    Qt5 UI信号.槽自动连接的控件重名 来源 http://blog.csdn.net/goldenhawking/article/details/51865909 对Qt5稍有熟悉的童鞋都知道信号. ...

  3. 【题解】CF#713 E-Sonya Partymaker

    这题真的想了挺久的,然而到最后也还是没想到怎样处理环的情况……网上竟然也完全没有题解,无奈之下到 CF 的 AC 代码里面去找了一份膜拜了一下.感谢~ 由于觉得这题有一定的难度,自己看代码也看了比较久 ...

  4. Visual Format Language(VFL)视图约束

    约束(Constraint)在IOS编程中非常重要,这关乎到用户的直接体验问题. IOS中视图约束有几种方式,常见的是在IB中通过Pin的方式手动添加约束,菜单Editor->Pin->. ...

  5. Zabbix3.4.5部署安装(二)

    一.部署环境 一)系统环境: [root@Node3 ~]# cat /etc/redhat-release //查看系统版本 CentOS Linux release (Core) [root@No ...

  6. winform登录代码

    Program.cs文件中 static class Program { /// <summary> /// 应用程序的主入口点. /// </summary> [STAThr ...

  7. jsonP 后台写法 及 层级树型数据递归查询

    Controller层: package com.taotao.rest.controller; import org.springframework.beans.factory.annotation ...

  8. Libevent学习笔记(四) bufferevent 的 concepts and basics

    Bufferevents and evbuffers Every bufferevent has an input buffer and an output buffer. These are of ...

  9. 金牌架构师:我们是这样设计APP数据统计产品的

    前言:近期,智能大数据服务商“个推”推出了应用统计产品“个数”,今天我们就和大家来谈一谈个数实时统计与AI数据智能平台整合架构设计. 很多人可能好奇,拥有数百亿SDK的个推,专注消息推送服务多年,现在 ...

  10. duilib 给List表头增加百分比控制宽度的功能

    转载请说明原出处,谢谢~~:http://blog.csdn.net/zhuhongshu/article/details/42503147 最近项目里需要用到包含表头列表,而窗体大小改变后,每个列表 ...