一、一个真正的react组件编译后长啥样?

我们瞎几把解读了react 虚拟dom对象是怎么生成的,生成了一个什么样的解构。一个react组件不光由若干个这些嵌套的虚拟dom对象组成,还包括各种生命周期钩子、自定义方法、事件等组成

下面让我们继续探索

react组件写法:

  1. // 一个再普通不过的react组件写法
  2.  
  3. mport React,{Component} from 'react';
  4. import Header from '../components/header';
  5. class Home extends Component {
  6. constructor(props){
  7. super(props);
  8. }
  9. componentWillMount(){
  10. console.log('willMount');
  11. }
  12. handleClickEvent(){
  13. console.log('click');
  14. }
  15. render(){
  16. let {name} = this.props;
  17. return (
  18. <div ref="home">
  19. <Header kk="js"/>
  20. <div>主页:{name}</div>
  21. <div>
  22. <p onClick={this.handleClickEvent}>哈哈哈哈</p>
  23. </div>
  24. </div>
  25. )
  26. }
  27. }
  28.  
  29. export default Home;

react组件被babel-preset-react编译后

  1. var Home = function (_Component) {
  2. _inherits(Home, _Component);
  3.  
  4. function Home(props) {
  5. _classCallCheck(this, Home);
  6.  
  7. return _possibleConstructorReturn(this, (Home.__proto__ || Object.getPrototypeOf(Home)).call(this, props));
  8. }
  9.  
  10. _createClass(Home, [{
  11. key: 'componentWillMount',
  12. value: function componentWillMount() {
  13. console.log('willMount');
  14. }
  15. }, {
  16. key: 'handleClickEvent',
  17. value: function handleClickEvent() {
  18. console.log('click');
  19. }
  20. }, {
  21. key: 'render',
  22. value: function render() {
  23. var name = this.props.name;
  24.  
  25. return _react2.default.createElement(
  26. 'div',
  27. { ref: 'home' },
  28. _react2.default.createElement(_header2.default, { kk: 'js' }),
  29. _react2.default.createElement(
  30. 'div',
  31. null,
  32. '\u4E3B\u9875:',
  33. name
  34. ),
  35. _react2.default.createElement(
  36. 'div',
  37. null,
  38. _react2.default.createElement(
  39. 'p',
  40. { onClick: this.handleClickEvent },
  41. '\u54C8\u54C8\u54C8\u54C8'
  42. )
  43. )
  44. );
  45. }
  46. }, {
  47. key: '__reactstandin__regenerateByEval',
  48. // @ts-ignore
  49. value: function __reactstandin__regenerateByEval(key, code) {
  50. // @ts-ignore
  51. this[key] = eval(code);
  52. }
  53. }]);
  54.  
  55. return Home;
  56. }(_react.Component);

通过看编译后的代码,我们得出以下关键词线索: React.Component

二、React.Component 又干了什么

Component来自于 ReactBaseClasses.js  找到他!

  1. import {Component, PureComponent} from './ReactBaseClasses';
  1. function Component(props, context, updater) {
  2. this.props = props; // 眼熟的props
  3. this.context = context; // context
  4. this.refs = emptyObject; // 初始化refs
  5. this.updater = updater || ReactNoopUpdateQueue;
  6. }
  7.  
  8. Component.prototype.isReactComponent = {};
  9. // 经典的setState 方法
  10. Component.prototype.setState = function(partialState, callback) {
  11. ...
  12. };
  13. // 强制重绘
  14. Component.prototype.forceUpdate = function(callback) {
  15. this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
  16. };

通过阅读代码,我们发现Component这个类的构成其实并不复杂,但其中的updater是一个很重要的东西,不过今天略过不表,脱离生命周期及dom渲染看updater没有任何意义,以后再说

同样setState也以后再说

通过js中的extends, 本文中的home组件获得了Component类中的所有属性和方法,我们再看源码,看看babel是如何拆解react组件生命周期的

三、defineProperty 的一顿猛操作

babel在解析jsx的时候自己定义了一堆模拟es6 extends、 class 、super的一堆东西

通过查看解析后的源码,我们可以知道其中奥秘

  1. var _createClass = function () {
  2. function defineProperties(target, props) {
  3. for (var i = 0; i < props.length; i++) {
  4. var descriptor = props[i];
  5. descriptor.enumerable = descriptor.enumerable || false;
  6. descriptor.configurable = true;
  7. if ("value" in descriptor) descriptor.writable = true;
  8. Object.defineProperty(target, descriptor.key, descriptor);
  9. }
  10. }
  11. return function (Constructor, protoProps, staticProps) {
  12. if (protoProps) defineProperties(Constructor.prototype, protoProps);
  13. if (staticProps) defineProperties(Constructor, staticProps);
  14. return Constructor;
  15. };
  16. }();
  17.  
  18. function _inherits(subClass, superClass) {
  19. if (typeof superClass !== "function" && superClass !== null) {
  20. throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);
  21. }
  22. subClass.prototype = Object.create(superClass && superClass.prototype, {
  23. constructor: {
  24. value: subClass,
  25. enumerable: false,
  26. writable: true,
  27. configurable: true
  28. }
  29. });
  30. if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ =
  31. superClass;
  32. }

一个仿造的继承,一个仿造的createClass

前者通过_inherits(Home,Component) 将 Component的prototype 赋予到Home上,使Home拥有了setState方法等等

后者通过  Object.defineProperty 将key-value形式的对象 赋予到 Home.prototype上

回首看被babel表一出来的react组件,那些钩子函数、自定义方法都被搞成了一个个key-value形式的对象,通过_createClass 给绑定到了Home类中

这样一个组件类就做好了,这个组件类的prototype里面有自定义函数、生命周期钩子函数、render方法

然后就是通过createElement又再次的封装成react 虚拟dom 被放到ReactDOM 中等待render

  1. // 编译前
  2. ReactDOM.render(
  3. <div>
  4. <Home name="home"/>
  5. </div>
  6. ,
  7. document.getElementById('app')
  8. );
  9.  
  10. // 编译后
  11. _reactDom2.default.render(_react2.default.createElement(
  12. 'div',
  13. null,
  14. _react2.default.createElement(_home2.default, { name: 'home' })
  15. ), document.getElementById('app'));

只不过这种虚拟dom和其他的不太一样,这种的对象里面的type类型是函数,而不是字符串罢了。所以可见 createElement返回对象的type不一定是字符串,是一切皆有可能

要知render中发生了什么,请听下回分解

四、本期留坑

setState 的解读,还没搞....

React 16 源码瞎几把解读 【二】 react组件的解析过程的更多相关文章

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

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

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

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

  3. React 16 源码瞎几把解读 【前戏】 为啥组件外面非得包个标签?

    〇.看前准备 1.自行clone react最新代码 2.自行搭建一个能跑react的test项目 一.看表面:那些插件 如何解析JSX 有如下一段代码: // ---- hearder.jsx 组件 ...

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

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

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

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

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

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

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

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

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

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

  9. 一步步实现windows版ijkplayer系列文章之六——SDL2源码分析之OpenGL ES在windows上的渲染过程

    一步步实现windows版ijkplayer系列文章之一--Windows10平台编译ffmpeg 4.0.2,生成ffplay 一步步实现windows版ijkplayer系列文章之二--Ijkpl ...

随机推荐

  1. Android四大组件之contentProvider

    Activity,Service,broadcast and Contentprovider android 4 大组件. ContentProvider:使用: public class Image ...

  2. day 05 万恶之源-基本数据类型(dict)

    05. 万恶之源-基本数据类型(dict)本节主要内容:1. 字典的简单介绍2. 字典增删改查和其他操作3. 字典的嵌套⼀一. 字典的简单介绍字典(dict)是python中唯⼀一的⼀一个映射类型.他 ...

  3. HN2018省队集训

    HN2018省队集训 Day1 今天的题目来自于雅礼的高二学长\(dy0607\). 压缩包下载 密码: 27n7 流水账 震惊!穿着该校校服竟然在四大名校畅通无阻?霸主地位已定? \(7:10\)从 ...

  4. word----遇到问题-----word中插入的图片无法左对齐----格式按钮为灰色

    当我们在用word时,有时要插入图片,却发现,插入的图片只在中间位置,不能拖到左边,这时怎么办呢 主要是图层的高低原因导致的不能拖动. 这个时候我们只需要设置一下图片的图层类型即可. 对着图片右键在设 ...

  5. 代码收藏系列--javascript--移动端技巧

    JS判断是否是手机端访问: var is_mobi = navigator.userAgent.toLowerCase().match(/(ipod|iphone|android|coolpad|mm ...

  6. 《剑指offer》— JavaScript(6)旋转数组的最小数字

    旋转数组的最小数字 题目描述 把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. 输入一个非递减排序的数组的一个旋转,输出旋转数组的最小元素.例如数组{3,4,5,1,2}为{1,2, ...

  7. hihocoder 1509异或排序

    描述 给定一个长度为 n 的非负整数序列 a[1..n] 你需要求有多少个非负整数 S 满足以下两个条件: (1).0 ≤ S < 2^60 (2).对于所有 1 ≤ i < n ,有 ( ...

  8. mac下php添加openssl扩展

    进入php源码目录 cd ext/openssl mv config0.m4 config.m4 phpize && ./configure  && make & ...

  9. JS事件大全及兼容

    一般事件 事件 浏览器支持 描述 onClick IE3|N2|O3 鼠标点击事件,多用在某个对象控制的范围内的鼠标点击 onDblClick IE4|N4|O 鼠标双击事件 onMouseDown  ...

  10. NOIP模拟5

    期望得分:100+100+100=300 实际得分:72+12+0=84 T1  [CQOI2009]中位数图 令c[i]表示前i个数中,比d大的数与比d小的数的差,那么如果c[l]=c[r],则[l ...