props react 源码_react super(props)与vue props - CSDN
  • React源码阅读:概况

    2019-02-28 09:11:20
    前言 本文主要介绍一些React的设计思想和相关...React源码阅读:虚拟DOM的初始化 项目结构 React的相关代码都放在packages里。 ├── packages ------------------------------- React实现的相关代码 │ ├── ...

    前言

    本文主要介绍一些React的设计思想和相关概念,不管是想要阅读源码还是想深入了解React的同学看过来呀。欢迎指出错误,一起探讨一起进步。

    React阅读系列文章

    React源码阅读:虚拟DOM的初始化

    项目结构

    React的相关代码都放在packages里。

    ├── packages ------------------------------- React实现的相关代码
    │   ├── create-subscription ------------------------- 在组件里订阅额外数据的工具
    │   ├── events -------------------------- React事件相关
    │   ├── react-art ------------------------- 画图相关库
    │   ├── react-dom -------------------------- ReactDom
    │   ├── react-native-renderer ----------------------------- ReactNative
    │   ├── react-reconciler ------------------------ React调制器
    │   ├── react-scheduler ------------------------ 规划React初始化,更新等等
    │   ├── react-test-renderer ------------------------ 实验性的React渲染器
    │   ├── shared ------------------------ 公共代码
    │   ├── simple-cache-provider ------------------------ 为React应用提供缓存
    复制代码

    主要思想和设计原则

    组合

    React的主要特性就是各种组合而成的组件。由不同人编写的组件可以组合使用,并且实现组件的复用。

    时序安排(Scheduling)

    React的初始化,更新,移除等等操作并不是同步的,用户编写的组件(如<ReactComponent/>)或者平台特定组件(如<div/>)这些只是返回需要渲染的信息,并不是真实DOM,我们通常称他们为虚拟DOM,React会遍历这颗虚拟DOM树来渲染真实的DOM树。

    而且setState()也并不是同步的,他们的多次调用更新会被整合为一次更新,加入更新队列然后等待更新,再去渲染真实的DOM树,因为DOM型的操作通常是很耗时的,所以尽量减少DOM相关操作。

    DOM之外

    React的一个主要特点为编写的代码可以通过工具(如ReactNative,Electron)在多个平台上运行,因此渲染出来的元素可能不是DOM,因此React将他们分为两个模块,一个模块为reconciler(调节器),它根据用户编写的组件转换为React可以识别的元素(即虚拟DOM);另一个模块为renderer(渲染器,分为DOM渲染器和Native渲染器),它的作用为根据虚拟DOM渲染为平台特定的元素。这样的好处是可以方便React可以在多平台上运行,而不必太过关注reconciler的代码。

    相关概念

    Fiber

    什么是Fiber?

    Fiber是React版本16以后的重要概念。

    Fiber的主要目标为:

    • 先暂停目前的工作去处理优先级更高的工作,然后再回来继续
    • 为不同的工作设定不同优先级
    • 重用之前完成的工作
    • 终止不再需要的工作

    我们都知道调用函数时会把它加入执行栈中,等函数执行完后再退出栈,那有没有办法可以定制栈的调用以更好地优化渲染UI呢?这就是Fiber想要解决的问题,我们可以称单个Fiber为虚拟的栈帧,它是实现React时序安排的关键。

    Fiber的结构

    type Fiber = {|
      //  辨识组件相关的属性
      tag: TypeOfWork,
      key: null | string,
      type: any,
      
      //  父Fiber或者null
      return: Fiber | null,
    
      child: Fiber | null,
      sibling: Fiber | null,
      index: number,
      ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject,
    
      memoizedProps: any, // The props used to create the output.
      updateQueue: UpdateQueue<any> | null,
      memoizedState: any,
      
      mode: TypeOfMode,
    
      effectTag: TypeOfSideEffect,
      nextEffect: Fiber | null,
      firstEffect: Fiber | null,
      lastEffect: Fiber | null,
      
      expirationTime: ExpirationTime,
    
      alternate: Fiber | null,
    
      //  时间
      actualDuration?: number,
      actualStartTime?: number,
      selfBaseTime?: number,
      treeBaseTime?: number,
    
     //  调试
      _debugID?: number,
      _debugSource?: Source | null,
      _debugOwner?: Fiber | null,
      _debugIsCurrentlyTiming?: boolean,
    |};
    复制代码

    keytype

    这两个属性都是用来表示组件的,更新组件的时候先检查key是否有改变,如果改变的话则直接摧毁重建;不变的话则继续检查type是否改变,改变则直接摧毁重建;否则重用原来的组件,只是改变组件的属性。type可能是用户定义的函数型或者类型的组合型组件,或者是代表平台元素的字符串(如'div')。

    pendingPropsmemoizedProps

    概念上来说,props就是一个函数的参数数组。pendingProps是Fiber开始执行的时候被设定的,memoizedProps在执行完之后。每次更新的时候先比较pendingPropsmemoizedProps,如果它们相同,则表示先前的输出可以重用,而不必进行多余的工作。

    pendingWorkPriority

    一个表面工作优先权的属性。除NoWork(它的值为0)以外,数值越大代表有限权越低。

    function matchesPriority(fiber, priority) {
      return fiber.pendingWorkPriority !== 0 &&
             fiber.pendingWorkPriority <= priority
    }
    复制代码

    参考文献

    展开全文
  • React源码分析1 -- 框架

    2017-03-02 16:33:14
    1 源码结构我们分析的React源码version为16.0.0-alpha.3,源码目录如下图所示。含义如下 addons:插件,一些比较有用的工具,如transition动画 isomorphic: 同构,服务端在页面初次加载时,将所有方法渲染好,一次性...

    1 源码结构

    我们分析的React源码version为16.0.0-alpha.3,源码目录如下图所示。

    Markdown

    含义如下

    • addons:插件,一些比较有用的工具,如transition动画
    • isomorphic: 同构,服务端在页面初次加载时,将所有方法渲染好,一次性交给客户端。这样可以减少Ajax
    • shared: 共用方法,一些utils
    • test: 测试方法
    • renderers: React代码核心,大部分功能实现代码都在其中
      • dom:
      • stack/client: 各种ReactComponent
      • stack/server: 服务端渲染方法
      • shared: CSSProperty, DOMProperty, 合成事件处理,DOM操作方法,如findDOMNode, setInnerHTML等。
      • fiber: 重写了React核心算法,架构进行了升级,未来可能会应用。
      • native: ReactNative, 跨平台实现Android和iOS
      • shared:
      • stack/reconciler: 协调器,包含自定义组件实现ReactCompositeComponent.js, setState机制,生命周期方法流程,DOM diff等
      • shared/event: 事件处理
      • fiber:实验代码,未来可能会应用

    2 重要模块

    React代码还是相当复杂的,我们需要深入理解重要模块的源码机制。后面会有几篇文章针对每个模块进行分析

    • 元素和组件的创建:ReactElement元素是一个数据类,包含props refs key等变量。ReactComponent是一个控制类,包含组件状态,操作方法等,是React对内的一个很重要的类。它有不同的子类实现,如DOM原生组件ReactDOMComponent,React自定义组件ReactCompositeComponent,文本组件ReactDOMTextComponent。

      React利用createClass()创建组件类对象,createElement()创建组件实例对象。JSX经过babel转译后,实际是调用createElement()创建实例对象。这部分代码分析参见 React源码分析2 — 组件和对象的创建(createClass,createElement)

    • React组件插入DOM流程:创建了ReactElement和ReactComponent后,还需要将virtual DOM插入真实DOM中,这样浏览器才能渲染。React会利用virtual DOM生成HTML,然后将HTML插入父组件中。而root组件正好是我们在ReactDOM.render()方法中传入的DOM原生对象。这部分代码分析参见 React源码分析3 — React组件插入DOM流程

    • React生命周期:React吸引人的一个地方在于,有比较清晰的生命周期调用方法。利用模板模式使得代码结构清晰而又不失灵活性。前端一直以来有个让人诟病的地方在于,大家代码风格各异,没有像Android那样比较清晰的流程方法,使得维护起来比较麻烦。React的出现大大解决了这个难题。这部分代码分析参见 React源码分析4 — React生命周期详解

    • setState实现机制:作为一种前端流行框架,虽然React专注于MVVM中的View,但它也实现了一套View和数据绑定的方法。这个正是setState。同时,利用队列和transaction来管理setState,避免了一些重复无谓的界面更新。这部分代码分析参见 React源码分析5 — setState机制

    总之,作为当下前端最流行的框架,React源码还是值得我们细细分析的。从源码中我们也能学到很多优秀的设计模式,让我们的代码更加清晰好维护。文章中如有不正确的地方,欢迎指正!

    展开全文
  • 【Vue原理】Props - 源码版 写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本【2.5.17】 如果你...

    【Vue原理】Props - 源码版

    写文章不容易,点个赞呗兄弟 专注 Vue 源码分享,文章分为白话版和 源码版,白话版助于理解工作原理,源码版助于了解内部详情,让我们一起学习吧 研究基于 Vue版本 【2.5.17】

    如果你觉得排版难看,请点击 下面链接 或者 拉到 下面关注公众号也可以吧

    【Vue原理】Props - 源码版

    今天记录 Props 源码流程,哎,这东西,就算是研究过了,也真是会随着时间慢慢忘记的。

    幸好我做了详细的文章,忘记了什么的,回忆起来必然是很快的。

    好的,回到正题,Props

    请你在读这篇之前,先去看看我的白话版

    【Vue原理】Props - 白话版

    在上面这篇文章中,也已经清楚地解决了一个问题

    父组件 如何 把数据 当做 props 传给子组件

    所以今天,我们只需记录 Props 的处理流程源码即可


    初始化

    在创建Vue实例的过程中,会调用 initState 处理options,比如 props,computed,watch 等

    只要你 new Vue 创建实例之后,很快就会处理options

    function Vue(){
        ... 其他处理
        initState(this)
    
        ...解析模板,生成DOM 插入页面
    
    }
    
    function initState(vm) {    
    
        var opts = vm.$options;    
    
        if (opts.props) {
    
            initProps(vm, opts.props);
        }
    
        ... 处理 computed,watch,methods 等其他options
    
    }
    

    initProps

    你看到处理 Props ,主要用到了一个方法 initProps,他就是本场的焦点了,让我们来采访下源码本码

    function initProps(vm, propsOpt) {    
       // 这是父组件给子组件传入的 props 的具体值
    
       var propsData = vm.$options.propsData || {};    
    
       var props = vm._props = {};    
    
       for (var key in propsOpt){        
    
           // 给 props 的 key 设置 响应式
    
           defineReactive(props, key,  propsData[key]);        
    
           if (! (key in vm)) {            
    
               // 转接访问,访问 vm 属性,转到访问 vm._props 属性
               proxy(vm, "_props", key);
           }
       }
    }
    

    上面的代码主要做了三件事

    1、遍历 props

    2、给 props 设置响应式

    3、给 props 设置代理

    我们主要讲两件事

    1、给 props 设置响应式

    defineReactive(props, key,  propsData[key])
    

    defineReactive 在这里就不给太多源码了,你只需要记住他就是给 props 设置响应式的

    function defineReactive(obj, key) {    
    
        Object.defineProperty(obj, key, {  
    
            get() { ...依赖收集 },
            set(newVal) { ....依赖更新 }
        });
    }
    

    如果你想了解响应式,就可以看我这篇文章

    【Vue原理】响应式原理 - 白话版

    Props 设置响应式,也是旨在数据改变时动态更新。

    怎么设置响应式吗?看这里

    【Vue原理】依赖收集 - 源码版之基本数据类型

    【Vue原理】依赖收集 - 源码版之引用数据类型

    数据是直接从 父组件上传过来的,没有进行拷贝等处理,原样传过来

    怎么传的?也可以看

    【Vue原理】Props - 白话版

    如果props 是基本类型

    在 子组件实例上设置这个 props 属性为响应式,跟 data 本质一样,作用是监听 props 修改

    如果 props 是对象

    也会在 子组件实例上 设置这个 props 属性为响应式,作用也是监听 props 修改

    但是!

    【不会递归对象】给对象内所有属性设置响应式,因为该对象【已经在父组件中】完成响应式设置了

    也就是说

    如果你在 子组件中直接修改 props 对象内的数据,父组件也会跟着修改

    在记录的途中,我发现了一个问题,发现没有想象中的那么简单,所以现在郑重记录

    当 父组件数据 改变,子组件怎么更新?

    分类型的,说得比较详细,可能有点绕?

    1、 如果是基本类型,是这个流程

    父组件数据改变,只会把新的数据传给子组件

    子组件拿到新数据,就会直接替换到原来的 props

    替换就是直接等哈,看下源码,重要语句标红

    updateChildComponent 是子组件内部更新时会调用到的一个函数,这是其中更新 props 的一个片段

    function updateChildComponent(
    
        vm, propsData
    
    ) {    
    
        if (propsData && vm.$options.props) {        
    
          // 保存 props 的地方,用于访问转接,具体看文章下面
    
          var props = vm._props;        
    
          // 所有子组件上设置的 props 的 key
    
          var propKeys = vm.$options._propKeys || [];        
    
          for (var i = 0; i < propKeys.length; i++) {            
    
            var key = propKeys[i];
    
            props[key] = propsData[key]
          }
         vm.$options.propsData = propsData;
       }
    }
    

    而 props 在子组件中也是响应式的,【直接 等号 替换】导致触发 set,set 再通知 子组件完成更新

    公众号

    公众号

    数据是 基本类型,然后设置定时器修改数据

    watcher1 是父组件,watcher2 是子组件

    父组件内的 data num 通知 watcher1 更新 子组件内的 props child_num 通知 watcher2 更新

    公众号

    2、如果是对象,是这个流程

    条件

    父组件传 对象 给 子组件,并且父子组件 页面都使用到了这个数据

    结果

    那么这个对象,会收集到 父子组件的 watcher

    所以

    当 对象内部被修改的时候,会通知到 父和子 更新。

    例子

    父组件设置 obj 对象,并传给子组件

    公众号

    公众号 定时修改父组件数据 obj.name ,可以看到是 obj.name 通知 父子更新

    公众号

    当然,如果对象被整个替换了,而不是修改内部,那么跟 基本类型一样

    区别是什么?

    1、基本类型是,子组件内部 props 通知 子组件更新的

    2、引用类型是,父组件的数据 data 通知 子组件更新的

    2、给 props 设置代理

    在白话版中,我已经说得很清楚了, Props 有个移花接木的暗箱操作,就是访问转移

    Data 也是这么做的


    【Vue原理】代理 Data - 源码版

    你在项目中,会使用 http://this.xxx去访问 props,props 已经当成了 实例的属性,所以可以直接访问

    但是其实你访问的是 【this._props.xxx】

    为什么 Vue 要这么弄,目的就是为了方便开发啊,让我们直接简短了相关代码

    而 React,访问 props,还要 this.props.xxxx,写这么长,不嫌麻烦吗?

    那么,是怎么设置代理的呢,就是下面这行

    proxy(vm, "_props", key);
    

    proxy 是什么也不要急,瓜就在下面,拿凳坐好

    function proxy(
    
        target, sourceKey, key
    
    ) {    
    
      Object.defineProperty(target, key, {
    
          get() {            
    
              return this[sourceKey][key]
    
          },
    
          set(val) {            
    
              this[sourceKey][key] = val;
    
          }
      });
    }
    

    这段代码做了2 个事

    1、使用 props 在 vm 上占位,使得可以通过 http://vm.xxx 的形式访问到 props

    2、设置 [Object.defineProperty] 的 get 和 set ,间接获取和赋值 vm._props

    所有访问赋值 props,转接到 vm._props 上,直观如下图

    公众号 上个实例,方便大家看

    公众号

    说完收工

    公众号

    展开全文
  • import React from 'react'; class App extends React.Component { render() { return <div>{this.props.name}</div> } } App.defaultProps = { name: "Hello React" }; ReactDOM.render(<...
    首先我们回顾一下 defaultProps 的用法
    import React from 'react';
     
    class App extends React.Component {
      render() {
        return <div>{this.props.name}</div>
      }
    }
     
    App.defaultProps = {
      name: "Hello React"
    };
     
    ReactDOM.render(<App />, document.getElementById('root'));
    

    这样我们就可以得到一个渲染出Hello React的界面啦。

    此时的关键,在于需要理解 ReactDOM.render 实际执行了什么方法。

    经过断点调试,我们可以清晰的看到

    代码从

    ReactDOM.render(<App />, document.getElementById('root'))
    

    React.createElmentWithValidation(type, props, children)
    

    由于 createElementWithValidation 并不是我想了解的重点,简要看了一下,大概执行了以下3步。

    判断第一个参数(示例代码中的 是否是有效元素 ), 如果不正确,你就会看到 React.createElement: type is invalid , 这个熟悉又亲切的报错

    执行 React.createElement(type, props, children)

    检查元素的 props 是否符合 propTypes 的约定

    其中对我们理解defaultProps有帮助的是第2步,React.createElement

    我们可以看到在源码地址的第221行中,写着清晰的注释 Resolve default props 。

    // Resolve default props
    if (type && type.defaultProps) {
      const defaultProps = type.defaultProps;
      for (propName in defaultProps) {
        if (props[propName] === undefined) {
          props[propName] = defaultProps[propName];
        }
      }
    }
    

    通过刚才的分析,我们可以知道上文代码中的 type 正是 App 对象。所以这里对 type.defaultProps 使用,就豁然开朗了。

    根据这段代码,我们更加可以印证,上一篇文章中提到多余的 defaultProps 确实会对代码的性能造成影响。

    因为当 type.defaultProps 存在时,是需要对其进行遍历的。

    所以如果你的文件中存在很多处这种无效的代码,虽然并不会对界面产生任何影响,但是确实影响了代码的质量。


    总结

    勿以善小而不为,勿以恶小而为之。注意自己的实现细节,提高代码质量。
    React 如此厉害的框架,除了优秀的架构和出色的算法,其实也离不开这些普普通通的很好理解的代码。

    展开全文
  • React源码系列(一): 总结看源码心得及方法感受 React源码系列(二): 从jsx到createElement React源码系列(三): ReactRoot的创建以及调度工作scheduleWork的执行 React源码系列(四): Fiber Tree &amp;&amp;...

    React源码系列(一): 总结看源码心得及方法感受

    React源码系列(二): 从jsx到createElement

    React源码系列(三): ReactRoot的创建以及调度工作scheduleWork的执行

    React源码系列(四): Fiber Tree && commit

    React源码系列(五): 新 ContextAPI

     

    我们先思考两个问题

    • 浏览器是怎么识别我们写的jsx?
    • 为什么甚至在我们的代码并没有使用 React 的情况下,也需要在文件顶部写 import React from 'react'

    jsx

    首先,什么是jsx?

    jsx 一种 JavaScript 的语法扩展,你可以在里面写你的 html + js。

    jsx

    然后babel就会帮我们调用 React.createElement。 这也是为什么我们就算文件内没用到 React,也需要引入的原因。 以下两种写法的结果是一样的,一个是手动调用,一个是babel帮忙做了这层操作。

    jsx-createelement

    createElement(type, [config], [childrens])文件传送

    createElement 是将jsx转为 ReactElement的函数, 我们把 Element 标签打印出来可以看到这个对象就是我们所说的ReactElement
    reactelement

    这里面主要是处理一下 key, ref, defaultProps, 然后将其他的参数和 childrens 放到props对象,最后调用ReactElement。

    我们再来看个复杂一点的例子,这个例子我们有多个childrend,而且有多个层级,这时候 babel会根据我们的jsx结构,从子级一层一层调用createElement,并把返回的 reactElement 作为父级的children,所以这里的 childrens 其实可以理解成是一棵 React Element Tree。

    jsx-createelement2
    react-element-tree

    上面我们写的都是直接写jsx,如果是一个 Class 形式的ReactComponent,其实也一样,只是type从原来的dom标签变成传入的类。

    react-element-class

    关于React.Component其实可以理解为只是简单的为一个类,里面包含一些属性,原型链上写了几个公用的方法,后面会针对某些方法(setState)拿出来讲。
    react-component

    到这一步,我们只是做了从jsx语法到React Element的转换,但基本上React库的部分就到这里了。

    你没有看错,react库其实提供的API就那么几个,如 createElement, Component, createContext等。剩下的大部分其实都抽象到 React-dom,react-scheduler等其他库,也是这种抽象使得React拥有跨平台的优势。

    展开全文
  • react源码阅读-基础

    2019-12-28 22:40:50
      react包基础概念以及React包的两个核心api阅读。阅读React包的源码版本为16.8.6。 基础概念 react包   react包的本质上是建立一个react相关数据类型的抽象屏障,它创建了一系列符合react渲染调度的数据结构,...
  • 阅读源码成了今年的学习目标之一,在选择 Vue 和 React 之间,我想先阅读 React 。 在考虑到读哪个版本的时候,我想先接触到源码早期的思想可能会更轻松一些,最终我选择阅读 0.3-stable 。 那么接下来,我将从几个...
  • 本文阅读react16.8.6版本ReactChildren.js...请参考React源码阅读本文。 mapChildren遍历每个子节点调用函数并摊平子节点。 摊平子节点,即,把['a', ['b'], [['c'], 'd']]摊平成['a', 'b', 'c', 'd'...
  • 阅读源码成了今年的学习目标之一,在选择 Vue 和 React 之间,我想先阅读 React 。 在考虑到读哪个版本的时候,我想先接触到源码早期的思想可能会更轻松一些,最终我选择阅读 0.3-stable 。 那么接下来,我将从几个...
  • React 把组件看作状态机(有限状态机), 使用state来控制本地状态, 使用props来传递状态. 前面我们探讨了 React 如何映射状态到 UI 上(初始渲染), 那么接下来我们谈谈 React 时如何同步状态到 UI 上的, 也就是: React...
  • 1 React生命周期流程调用流程可以参看上图。分为实例化,存在期和销毁三个不同阶段。介绍生命周期流程的文章很多,相信大部分同学也有所了解,我们就不详细分析了。很多同学肯定有疑问,这些方法在React内部是在哪些...
  • 其实react和vue思想差不多,render生成虚拟节点,对比改变真实节点响应。   <!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title>Hello React!</title&...
  • React的主要思想是通过构建可复用组件来构建用户界面。组件:其实就是有限状态机,通过状态渲染对应的界面,且每个组件都有自己的生命周期,它规定了组件的状态和方法需要在那个阶段改变和执行。例如:某个组件有...
  • 这是 React 源码解析系列第一篇文章,系列文章基于 v16.8.6版本。 Hooks 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。 Hooks 非常简单,比如 useState 可以在 ...
  • React源码系列文章,请多支持:React源码分析1 — 组件和对象的创建(createClass,createElement)React源码分析2 — React组件插入DOM流程React源码分析3 — React生命周期详解React源码分析4 — setState机制React...
  • 1 React合成事件特点React自己实现了一套高效的事件注册,存储,分发和重用逻辑,在DOM事件体系基础上做了很大改进,减少了内存消耗,简化了事件逻辑,并最大化的解决了IE等浏览器的不兼容问题。与DOM事件体系相比,...
  • 作用:因为react中Function Component是没有实例的,没有办法进行传递ref。所以,就产生了React.forwardRef这个API来解决这个问题。export default function forwardRef<Props, ElementType: React$ElementType&...
  • react源码-事件监听

    2019-06-11 15:00:08
    react源码的 react-dom/src/events/ReactBrowserEventEmitter.js文件的开头,有这么一大段注释: 事件委托是很常用的一种浏览器事件优化策略,于是 React就接管了这件事情,并且还贴心地消除了浏览器间的差异,...
  • connect源码分析 connect使用方式 import React, { Component } from 'react' import { connect } from './react-redux' class App extends Component { render () { return ( <div> <p &g...
  • react源码分析

    2017-05-23 11:03:44
    原文地址:http://www.html-js.com/article/JS-analysis-of-the-single-row-from-zero-reactjs-source-first-rendering-principle%203154 前端的发展特别快,经历过jQuery一统天下的工具库时代后,现在各种框架又...
1 2 3 4 5 ... 20
收藏数 6,453
精华内容 2,581
关键字:

props react 源码