zoukankan      html  css  js  c++  java
  • 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" },
            "u6211u662Fheader.",
            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,
                        'u4E3Bu9875'
                    ),
                    _react2.default.createElement(
                        'div',
                        null,
                        _react2.default.createElement(
                            'p',
                            null,
                            'u54C8u54C8u54C8u54C8'
                        )
                    )
                );
            }
        }, {
            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" },
            "u6211u662Fheader.",
            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是否在一个闭合标签中,同时是否语法正确

  • 相关阅读:
    网络营销高人的八点心得/搜索引擎推广方法
    先富者的生活方式,必须注重质量
    知识素养
    成功创业的20条法则, 成为行业中世界顶尖
    ]梦想因人的追逐而变的伟大!
    职场做人既要对事也要对人
    宽恕:管理人的最佳武器
    别了,2006
    让你在职场游刃有余的10句话
    开发客户的十大传世技巧
  • 原文地址:https://www.cnblogs.com/JhoneLee/p/9407854.html
Copyright © 2011-2022 走看看