精华内容
下载资源
问答
  • 对react渲染原理的理解
    2021-11-08 14:35:27

    [react] 说说你对React的渲染原理的理解

    1.单向数据流。React是一个MVVM框架,简单来说是在MVC的模式下在前端部分拆分出数据层和视图层。单向数据流指的是只能由数据层的变化去影响视图层的变化,而不能反过来(除非双向绑定)
    2.数据驱动视图。我们无需关注页面的DOM,只需要关注数据即可
    3.渲染过程,生命周期……
    4.setState()大部分时候是异步执行的,提升性能。

     个人简介

    我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易,
    但坚持一定很酷。欢迎大家一起讨论



    主目录

    与歌谣一起通关前端面试题

    更多相关内容
  • React之React渲染原理

    2020-10-20 19:25:12
    文章目录一、react如何将代码显示到页面上(1)JSX生成Element1. JSX语法2. 使用babelJSX语法进行转换3. 创建虚拟Dom(2)Element生成Dom 一、react如何将代码显示到页面上 每当我们新建react项目时,项目创建成功...

    一、react如何将代码显示到页面上

    每当我们新建react项目时,项目创建成功后,运行npm start后会出现如下界面:
    在这里插入图片描述
    可以观察到时app.js中对该页面进行的设计,代码如下:
    在这里插入图片描述
    观察index.js发现最终代码是在这里执行的:
    在这里插入图片描述
    React将代码显示出来主要有两个步骤:

    1. JSX转化为Element
    2. Element转化为Dom

    (1)JSX生成Element

    1. JSX语法

    可以看到第一个张图片中的render函数中return了一段html片段,这段片段就是JSX语法

    定义:JSX 即Javascript XML,它是对JavaScript 语法扩展。React 使用 JSX 来替代常规的 JavaScript。你也可以认为JSX其实就是JavaScript。当遇到<,JSX就当HTML解析,遇到{就当JavaScript解析。

    优点
    执行速度更快,因为它在编译为JavaScript代码后进行了优化

    2. 使用babel对JSX语法进行转换

    return (
        <div className="cn">
             <Header> Hello, This is React </Header>
             <div>Start to learn right now!</div>
             Right Reserve.
        </div>
    )
    

    通过babel编译成React.createElement的表达式。

    return (
        React.createElement(
            'div',
            { className: 'cn' },
            React.createElement(
                Header,
                null,
                'Hello, This is React'
            ),
            React.createElement(
                'div',
                null,
                'Start to learn right now!'
            ),
            'Right Reserve'
        )
    )
    

    当render函数被调用时,会执行React.createElement的表达式,返回Element元素

    3. 创建虚拟Dom

    调用React.createElement方法时,React 把真实的 DOM 树转换成 Javascript 对象树,会创建虚拟Dom树,也就是 Virtual Dom。

    每次数据更新后,重新计算 Virtual Dom ,并和上一次生成的 virtual dom 做对比,对发生变化的部分做批量更新。

    而 React 是通过创建与更新虚拟元素 Virtual Element 来管理整个Virtual Dom 的。


    虚拟元素可以理解为真实元素的对应,它的构建与更新都是在内存中完成的,并不会真正渲染到 dom 中去。

    虚拟dom 实际上是对实际Dom的一个抽象,是一个js对象。
    react所有的表层操作实际上是在操作Virtual dom。

    (2)Element生成Dom

    上一步通过JSX获得了虚拟Dom树,现在需要将虚拟Dom转化为真实的Dom,可以看到第二张图里的ReactDOM.render 方法。

    这时可以利用 ReactDOM.render 方法,传入一个 reactElement 和一个 作为容器的 DOM 节点。

    而这个方法查看到源码可以看见是调用了一个instantiateReactComponent函数,这个函数 创建了一个ReactComponent 的实例并返回,也可以看到 ReactDOM.render 最后返回的也是这个实例。
    代码如下:

        function instantiateReactComponent(node) {
          var instance;
        
          if (node === null || node === false) {
            instance = new ReactEmptyComponent(instantiateReactComponent);----------(1)
          } else if (typeof node === 'object') {
            var element = node;
            '
              如果 type的类型是string 则说明它是 普通的HTML标签,那么直接按照普通的方式生成 DOM
              
              而如果不是string的话,比如是
              ƒ ()  ƒ App(props)之类的,则说明他们是 自定义的组件。
              则要另行处理。
            '
            
            if (typeof element.type === 'string') {
                '
                ReactNativeComponent.createInternalComponent 方法是被注入进来的,注入的是 ReactDOMComponent 类。
                最终的结构是 new ReactDOMComponent(element.type,element.props)
        
                生成一个 ReactDOMComponent 的实例返回
                '
                
              instance = ReactNativeComponent.createInternalComponent(element);--------(2)
            } else if (isInternalComponentType(element.type)) {
              instance = new element.type(element);---------------(3)
            } else {
        
                '
                是我们自定义的类的时候 执行该方法来进行生成 instance 操作。
                '
              instance = new ReactCompositeComponentWrapper();----------(4)
              
            }
          } else if (typeof node === 'string' || typeof node === 'number') {
            instance = ReactNativeComponent.createInstanceForText(node);----------(5)
          } else {
            !false ? process.env.NODE_ENV !== 'production' ? invariant(false, 'Encountered invalid React node of type %s', typeof node) : invariant(false) : undefined;
          }
        
         
          instance.construct(node);
        
         
          instance._mountIndex = 0;
          instance._mountImage = null;
        
          return instance;
        }
    

    instantiateReactComponent 方法是初始化组件的入口函数,它通过判断 node 的类型来创建不同的react对象。

    • 当 node 为空的时候,初始化组件。
    • 当 node 为对象,类型 type 字段标记为是字符串,初始化 DOM 标签。否则初始化自定义组件。
    • 当 node 为字符串或者数字时,初始化文本组件。

    创建了 Component 实例后,调用 component 的 mountComponent 方法,注意到这里是会被批量 mount 的,然后就可以进行渲染。

    参考文章:https://cloud.tencent.com/developer/article/1520009

    展开全文
  • React渲染原理

    2021-02-11 07:50:25
    React渲染原理看了公众号的文章【第1386期】React从渲染原理到性能优化(一)​mp.weixin.qq.com,做一个简单的摘抄。侵权即删文中有一句话我是很赞同的其实渲染原理决定着性能优化的方法,只有在了解原理之后,才能...

    React渲染原理看了公众号的文章【第1386期】React从渲染原理到性能优化(一)​mp.weixin.qq.com30568f42ded6a3167a9eefb634df907e.png

    ,做一个简单的摘抄。侵权即删

    文中有一句话我是很赞同的其实渲染原理决定着性能优化的方法,只有在了解原理之后,才能完全理解为什么这样做可以优化性能。正所谓:知其然,然后知其所以然。

    按照原文结构,本文也分为四个部分。

    JSX如何生成element

    element如何生成真实DOM节点

    性能优化

    React16异步渲染方案

    1. JSX如何生成element

    先来看一下render里的jsx经过babel编译后的React.createElement;

    # render jsx

    return (

    hello

    start

    Right Reserve

    )

    # babel React.createElement

    return (

    React.createElement(

    'div',

    {

    className : 'cn'

    },

    React.createElement(

    Header,

    null,

    'hello'

    ),

    React.createElement(

    'div',

    null,

    'start'

    ),

    'Right Reserve'

    )

    )什么是createElement?

    生成element。element在React里是组成虚拟Dom树的节点。这个表达式会在render被调用的时候执行并返回一个element。它有三个参数:

    type -> 标签

    attributes -> 标签属性,若无则为null

    children -> 标签的子节点

    element的结构(不一定是Object类型)

    {

    type : 'div',

    props: {

    className : 'cn',

    children : [

    {

    type : function Header,

    props : {

    children : 'hello'

    }

    },

    {

    type : 'div',

    props : {

    children : 'start'

    }

    },

    'Right Reserve'

    ]

    }

    }children类型

    string

    原生dom节点

    React Component - 自定义组件

    false、null、undefined、number

    数组 - 使用map方法的时候

    Element如何生成真实节点

    初始化element规则如下: * 判断是否为Object类型 * yes -> 判断type是否为原生DOM标签 * yes -> 创建ReactDomComponent的实例对象。 * no -> 使用ReactCompositeCompontWrapper * no -> 判断类型 * string number -> 使用ReactDomTextComponent * null false -> 使用ReactDomEmptyComponent

    这里的ReactDOMComponent、ReactCompositeComponentWrapper是React的私有类,他们常用的方法有mountComponent、updateComponent等。其中mountComponent用于创建组件,而updateComponent用于用户更新组件,我们自定义组件的生命周期函数以及render函数都是在这些私有类的方法里被调用的。

    ReactDOMComponent

    首先是ReactMComponent的mountComponent方法,这个方法的作用是:将element转成真实DOM节点,并且插入到相应的container里,然后返回markup(realDOM)。

    由此可知ReactDOMComponent的mountComponent是element生成真实节点的关键。

    # `type`类型为原生DOM的`element`

    {

    type : 'div',

    props : {

    className : 'cn',

    children : 'hello world'

    }

    }

    # 简单`mountComponent`的实现(源码并非如此)

    mountComponent(container){

    const domElement = document.createElement(this._currentElement.type);

    const textNode = document.createTextNode(this._currentElement.props.children);

    domElement.appendChild(textNode);

    container.appendChild(domElment);

    return domElement;

    }

    这个类的mountComponent方法会自己操作浏览器DOM元素

    ReactCompositeComponentWrapper

    这个类的mountComponent方法作用是:实例化自定义组件,最后是通过递归调用到ReactDOMComponent的mountComponent方法来得到真实DOM。他自己是不直接生成DOM节点的。

    首次渲染(讲述递归过程)

    假设我们有一个Example的组件,它返回

    hello world
    这样一个标签。 初次渲染过程如下图

    从React render开始 render函数被调用的时候会返回一个element。

    {

    type : function Example,

    props : {

    children : null

    }

    }

    由于这个type是一个自定义组件类,此时要初始化的类是ReactCompositeComponentWrapper,接着调用它的mountComponent方法。这里面会做四件事情,详情可以看上图。其中,第二步的render的得到的element为:

    {

    type: 'div',

    props: {

    children: 'Hello World'

    }

    }

    由于这个type是一个原生DOM标签,此时要初始化的类是ReactDOMComponent。接下来它的mountComponent方法就可以帮我们生成对应的DOM节点放在浏览器里啦。

    如果第二步render出来的element类型还是自定义组件的时候,它就会去调用ReactCompositeComponentWrapper的mountComponent方法,从而形成了一个递归。

    由图可知,在第一步得到instance对象之后,就会去看instance.componentWillMount是否有被定义,有的话调用,而在整个渲染过程结束之后调用componentDidMount。

    2. element => 真实DOM节点

    触发组件的更新有两种更新方式:props以及state改变带来的更新。本次主要解析state改变带来的更新。整个过程流程图如下:

    1、一般改变state,都是从setState开始,这个函数被调用之后,会将我们传入的state放进pendingState的数组里存起来,然后判断当前流程是否处于批量更新,如果是,则将当前组件的instance放进dirtyComponent里,当这个更新流程中所有需要更新的组件收集完毕之后(这里面涉及到事务的概念,感兴趣的可以自己去了解一下)就会遍历dirtyComponent这个数组,调用他们的uptateComponent对组件进行更新。当然,如果当前不处于批量更新的状态,会直接去遍历dirtyComponent进行更新。

    2、在我们这个例子中,由于Example是自定义组件,所以调用的是ReactCompositeComponentWrapper这个类的updateComponent方法,这个方法做三件事。计算出nextState

    render()得到nextRenderElement

    与prevElement 进行Diff 比较(这个过程后面会介绍),更新节点

    最后这个需要去更新节点的时候,跟首次渲染一样,也需要调用ReactDOMComponent的updateComponent来更新。其中第二步render得到的也是自定义组件的话, 会形成递归调用。

    接下来,还是上次的问题:那么更新过程中的生命周期函数,shouldComponentUpdate,componentWillUpdate跟componentDidUpdate在哪被调用呢?

    由图可知,shouldComponentUpdate在第一步调用得到nextState之后调用,因为nextState也是它的其中一个参数嘛~这个函数很重要,它是我们性能优化的一个很关键的点:由图可以看到,当shouldComponentUpdate返回false的时候,下面的一大块都不会被去执行,包括已经被优化的diff算法。

    当shouldComponentUpdate返回true的时候,会先调用componentWillUpdate,在整个更新过程结束之后调用componentDidUpdate。

    以上就是更新渲染的过程。

    Diff算法

    React基于两个假设:两个相同的组件产生类似的DOM结构,不同组件产生不同DOM结构

    对于同一层次的一组子节点,它们可以通过唯一的id区分

    发明了一种叫Diff的算法来比较两棵DOM tree,它极大的优化了这个比较的过程,将算法复杂度从O(n^3)降低到O(n)。

    同时,基于第一点假设,我们可以推论出,Diff算法只会对同层的节点进行比较。如图,它只会对颜色相同的节点进行比较。

    也就是说如果父节点不同,React将不会在去对比子节点。因为不同的组件DOM结构会不相同,所以就没有必要在去对比子节点了。这也提高了对比的效率。

    下面,我们具体看下Diff算法是怎么做的,这里分为三种情况考虑节点类型不同

    节点类型相同

    子节点比较

    不同节点类型

    对于不同的节点类型,react会基于第一条假设,直接删去旧的节点,新建一个新的节点。

    比如:

    // change

    React会直接删掉A节点(包括它所有的子节点),然后新建一个B节点插入

    为了验证这一点,我打印出了从shape1到shape2节点的生命周期

    最后终端输出的结果是:

    Shape1 :

    A is created

    A render

    C is created

    C render

    C componentDidMount

    A componentDidMountShape2 :

    A componentWillUnmount

    C componentWillUnmount

    B is created

    B render

    C is created

    C render

    C componentDidMount

    B componentDidMount

    由此可以看出,A与其子节点C会被直接删除,然后重新建一个B,C插入。这样就给我们的性能优化提供了一个思路,就是我们要保持DOM标签的稳定性。

    打个比方,如果写了一个

    ,,此时即使List的内容不变,它也会先被卸载在创建,其实是很浪费的。

    相同节点类型

    当对比相同的节点类型比较简单,这里分为两种情况,一种是DOM元素类型,对应html直接支持的元素类型:div,span和p,还有一种是自定义组件。

    DOM元素类型

    react会对比它们的属性,只改变需要改变的属性 比如:

    这两个div中,react会只更新className的值

    这两个div中,react只会去更新color的值

    自定义组件类型

    由于React此时并不知道如何去更新DOM树,因为这些逻辑都在React组件里面,所以它能做的就是根据新节点的props去更新原来根节点的组件实例,触发一个更新的过程,最后在对所有的child节点在进行diff的递归比较更新。

    - shouldComponentUpdate

    - componentWillReceiveProps

    - componentWillUpdate

    - render

    - componentDidUpdate

    子节点比较

    // 列表一到列表二

    因为React在没有key的情况下对比节点的时候,是一个一个按着顺序对比的。从列表一到列表二,只是在中间插入了一个C,但是如果没有key的时候,react会把B删去,新建一个C放在B的位置,然后重新建一个节点B放在尾部。

    列表一:

    A is created

    A render

    B is created

    B render

    A componentDidMount

    B componentDidMount列表二:

    A render

    B componentWillUnmount

    C is created

    C render

    B is created

    B render

    A componentDidUpdate

    C componentDidMount

    B componentDidMount

    当节点很多的时候,这样做是非常低效的。有两种方法可以解决这个问题:

    1、保持DOM结构的稳定性,我们来看这个变化,由两个子节点变成了三个,其实是一个不稳定的DOM结构,我们可以通过通过加一个null,保持DOM结构的稳定。这样按照顺序对比的时候,B就不会被卸载又重建回来。

    {null}

    // 列表一到列表二

    2、key

    通过给节点配置key,让React可以识别节点是否存在。

    配上key之后,在跑一遍代码看看。

    A render

    C is created

    C render

    B render

    A componentDidUpdate

    C componentDidMount

    B componentDidUpdate

    果然,配上key之后,列表二的生命周期就如我所愿,只在指定的位置创建C节点插入。

    这里要注意的一点是,key值必须是稳定(所以我们不能用Math.random()去创建key),可预测,并且唯一的。

    这里给我们性能优化也提供了两个非常重要的依据:

    保持DOM结构的稳定性

    map的时候,加key

    未完待续

    展开全文
  • React Hooks 原理理解

    千次阅读 2022-01-29 18:20:55
    文章目录Hookshooks与fiber(workInProgress)状态派发——useState(useReducer)原理处理副作用——useEffect(useLayoutEffect)原理状态获取与缓存——useRef(useMemo)原理总结 Hooks 可参考之前文章:React ...

    Hooks

    可参考之前文章:React Hooks详解

    Hooks 出现

    没有Hooks时,函数组件能够做的只是接受 Props、渲染 UI ,以及触发父组件传过来的事件。

    有的处理逻辑都要在类组件中写,这样会使 class 类组件内部错综复杂,每一个类组件都有一套独特的状态,相互之间不能复用。

    Hooks 出现 本质原因

    • 让函数组件也能做类组件的事,有自己的状态,可以处理一些副作用,能获取 ref ,也能做数据缓存。
    • 解决逻辑复用难的问题。
    • 放弃面向对象编程,拥抱函数式编程。

    hooks与fiber(workInProgress)

    hooks 作为函数组件本身和函数组件对应的 fiber 之间的沟通桥梁。

    在这里插入图片描述
    hooks 对象本质上是主要以三种处理策略存在 React 中:

    • ContextOnlyDispatcher: 防止开发者在函数组件外部调用 hooks ,所以第一种就是 报错形态,只要开发者调用了这个形态下的 hooks ,就会抛出异常。
    • HooksDispatcherOnMount: 函数组件 初始化 mount ,hooks 是函数组件和对应 fiber 桥梁,这个时候的 hooks 作用就是建立这个桥梁,初次建立其 hooks 与 fiber 之间的关系。
    • HooksDispatcherOnUpdate:函数组件 更新 update,既然与 fiber 之间的桥已经建好了,那么组件再更新,就需要 hooks 去获取或者更新维护状态。

    hooks对象:

    const HooksDispatcherOnMount = { /* 函数组件初始化用的 hooks */
        useState: mountState,
        useEffect: mountEffect,
        ...
    }
    const  HooksDispatcherOnUpdate ={/* 函数组件更新用的 hooks */
       useState:updateState,
       useEffect: updateEffect,
       ...
    }
    const ContextOnlyDispatcher = {  /* 当hooks不是函数内部调用的时候,调用这个hooks对象下的hooks,所以报错。 */
       useEffect: throwInvalidHookError,
       useState: throwInvalidHookError,
       ...
    }
    

    函数组件触发

    在 fiber 调和过程中,到 FunctionComponent 类型的 fiber,调用 updateFunctionComponent 更新 fiber,内部就会调用 renderWithHooks

    renderWithHooks

    在这里插入图片描述

    1. hooks 内部通过 currentlyRenderingFiber 读取当前 fiber 信息。(workInProgress ——正在调和更新函数组件对应的 fiber 树)
    2. memoizedState 保存 hooks 信息。
    3. updateQueue 存放每个 useEffect / useLayoutEffect产生的副作用组成的链表。在 commit 阶段更新这些副作用。
    4. 判断组件是 初始化流程还是更新流程,如果初始化用 HooksDispatcherOnMount 对象,如果更新用 HooksDispatcherOnUpdate 对象
    5. 执行 Component ( props , secondArg ),里面每一个 hooks 也将依次执行。
    6. 函数组件执行完毕,将 hooks 赋值给 ContextOnlyDispatcher 对象

    1、hooks 初始化——hooks 和 fiber 建立起关系

    每一个hooks 初始化都会执行 mountWorkInProgressHook,将 hooks 和 fiber 建立起联系。

    mountWorkInProgressHook

    在这里插入图片描述

    • 函数组件对应 fiber 用 memorizedState 保存 hooks 对象
    • 每个 hooks 通过 next链表 建立关系

    2、hooks 更新

    双缓冲树 更新类似。参考: React 调和(Reconciler)原理理解

    即:取出 workInProgres.alternate 里面对应的 hook ,然后根据之前的 hooks 复制一份,形成 新的 hooks 链表关系,进行调和更新。

    问:React Hooks 为什么不能写在条件语句中?

    答:在更新过程中,如果通过 if 条件语句,增加或者删除 hooks,在复用 hooks 过程中,会产生复用 hooks 状态和当前 hooks 不一致的问题。


    状态派发——useState(useReducer)原理

    useState 和 useReducer 原理大同小异,本质上都是触发更新的函数都是 dispatchAction。

    执行useState()

    1、mountState

    在这里插入图片描述

    • state 会被当前 hooks 的 memoizedState 保存下来,每一个 useState 都会创建一个 queue 里面 保存了更新的信息

    • 每一个 useState 都会 创建一个更新函数 dispatchAction

    • 当前的 fiber 被 bind 绑定了固定的参数传入 dispatchAction 和 queue

    • 最后把 memoizedState,dispatch 返回 给开发者使用。

    2、dispatchAction
    在这里插入图片描述

    • 每一次调用 dispatchAction 都会先 创建一个 update ,然后把它 放入待更新 pending 队列中。
    • 判断如果当前的 fiber 正在更新,那么也就不需要再更新。
    • 反之,说明当前 fiber 没有更新任务,那么会拿出 上一次 state 和 这一次 state 进行对比
    • 如果相同,那么 直接退出更新
    • 如果不相同,那么 发起更新调度任务

    3、 updateReducer

    当再次执行useState的时候,会触发更新hooks逻辑,本质上调用的就是 updateReducer

    在这里插入图片描述

    • 把待更新的队列 pendingQueue 拿出来,合并baseQueue,循环进行更新。
    • 循环更新的流程,得到最新的 state 。
    • 接下来就可以从 useState 中得到最新的值

    处理副作用——useEffect(useLayoutEffect)原理

    在 render 阶段,实际没有进行真正的 DOM 元素的增加,删除,React 把想要做的不同操作打成不同的 effectTag ,等到 commit 阶段统一处理这些副作用,包括 DOM 元素增删改,执行一些生命周期等

    Hooks 中的 useEffect 和 useLayoutEffect 也是副作用。

    1、初始化
    在这里插入图片描述

    • mountWorkInProgressHook 产生一个 hooks ,并 和 fiber 建立起关系
    • 通过 pushEffect 创建一个 effect,并保存到当前 hooks 的 memoizedState 属性下。
    • pushEffect 除了创建一个 effect , 还有一个重要作用,就是如果存在多个 effect 或者 layoutEffect 会形成一个副作用链表,绑定在函数组件 fiber 的 updateQueue 上。独立形成链表结构,在 commit 阶段 统一处理和执行

    2、更新
    在这里插入图片描述

    • 判断 deps 项有没有 发生变化,如果没有发生变化,更新副作用链表
    • 如果发生变化,更新链表同时,打执行副作用的标签fiber => fiberEffectTag,hook => HookHasEffect。在 commit 阶段就会根据这些标签,重新执行副作用

    EffectTag

    React 会 用不同的 EffectTag 来标记不同的 effect

    • 对于useEffect 会用 HookPassive 标识符
    • 对于 useLayoutEffect 会用 HookLayout 的标识符

    React 就是在 commit 阶段,通过标识符,证明是 useEffect 还是 useLayoutEffect ,接下来 React 会同步处理 useLayoutEffect ,异步处理 useEffect

    • 如果函数组件需要更新副作用,会标记 UpdateEffect,哪个effect 需要更新,看 hooks 上有没有 HookHasEffect标记,所以初始化或者 deps 不相等,就会给当前 hooks 标记上 HookHasEffect ,所以会执行组件的副作用钩子。

    问:useEffect 和 useLayoutEffect 的区别?

    • useEffect 在渲染时是 异步执行,并且要等到浏览器将所有变化渲染到屏幕后才会被执行。
    • useLayoutEffect 在渲染时是 同步执行,其执行时机与 componentDidMount,componentDidUpdate 一致。在DOM更新完成后,里面的callback函数会立即执行,但是会在浏览器进行任何绘制之前运行完成,阻塞了浏览器的绘制。

    状态获取与缓存——useRef(useMemo)原理

    1、对于 ref 处理

    useRef :创建并维护一个 ref 原始对象。用于获取原生 DOM 或者组件实例,或者保存一些状态等。

    1)初始化

    • 创建 ref对象
      在这里插入图片描述

    2)更新

    • 取出复用 ref对象
      在这里插入图片描述

    useRef 的好处:

    useRef 可以创建出一个 ref 原始对象,只要组件没有销毁,ref 对象就一直存在,那么完全可以把一些不依赖于视图更新的数据储存到 ref 对象中。这样做的好处有两个:

    • 第一个能够直接修改数据,不会造成函数组件冗余的更新作用。
    • 第二个 useRef 保存数据,如果有 useEffect ,useMemo 引用 ref 对象中的数据,无须将 ref 对象添加成 dep 依赖项,因为 useRef 始终指向一个内存空间,所以这样一点好处是可以随时访问到变化后的值。

    2、对于 memo 处理

    useMemo:会记录上一次执行 create 的返回值,并把它绑定在函数组件对应的 fiber 对象上,只要组件不销毁,缓存值就一直存在,但是 deps 中如果有一项改变,就会重新执行 create ,返回值作为新的值记录到 fiber 对象上。

    1)初始化
    在这里插入图片描述

    • 会执行第一个函数得到想要缓存的值,将 值缓存 到 hook 的 memoizedState 上。

    2)更新
    在这里插入图片描述

    • 对比两次的 dep 是否发生变化,如果没有发生变化,直接返回缓存值,如果发生变化,执行第一个参数函数,重新生成缓存值,缓存下来,供开发者使用。

    总结

    1、hooks对象、初始化和更新

    2、状态派发

    3、处理副作用

    4、状态获取与缓存

    展开全文
  • 对React一些原理的理解 ... 陶德 Since 1997 10 人赞了该文章 ...刚开始出现问题时很懵,不知道该怎么解决,原因就是对React原理理解的不够透彻,不知道问题出在哪。在解决问题的过程中,也逐渐...
  • React Context 原理理解

    千次阅读 2022-01-29 10:29:11
    文章目录ContextContext 相关用法Context 原理总结 Context React提供了 Context 上下文模式,为了解决 props 每层都需要传递的问题,即Context 提供了一个无需为每层组件手动添加 props,就能在组件树间进行数据...
  • React State 原理理解

    2021-11-09 21:33:38
    setState:React 项目中 UI 的改变来源于 state 改变,类组件中 setState 是更新组件,渲染视图的主要方式。 用法:setState(obj,callback) 第一个参数: 当 obj 是一个对象,则为即将合并的 state 当 obj 是一个...
  • 帮助同学们彻底理解深入理解服务器端渲染及底层实现原理,课程学习完成,大家可以搭建属于自己的工程架构。适合人群需要有一定的React项目经验, 想要提升自己进军中高级工程行业的前端开发人员建议您先从《React16.4...
  • React Props 原理理解

    2022-01-12 10:26:46
    props 是 React 组件通信最重要的手段 props:对于在 React 应用中写的子组件,父组件绑定在它们标签里的 属性和方法,最终会变成 props 传递给它们。 1)props 可以是: ① props 作为一个子组件渲染数据源。 ② ...
  • 对于首次挂载阶段,我们需要了解react渲染流程是:通过我们书写的初始元素和一些其他可以生成虚拟节点的东西来生成虚拟节点。然后针对不同的节点类型去做不同的事情,最终将真实DOM挂载到页面上。然后执行渲染期间...
  • 我用 React 也挺久了,这篇文章就来总结一下我 react 原理理解react 和 vue 都是基于 vdom 的前端框架,我们先聊下 vdom:vdom为什么 react 和 vue 都要基于 vdom 呢?直接操作真实 dom 不行么?考虑下这样的...
  • 对React fiber的理解

    2022-08-26 20:04:35
    用户可能会感觉到卡顿而这也正是React 15的所面临的问题,当React渲染组件时,从开始到渲染完成整个过程是一气呵成的,无法中断如果组件较大,那么js线程会一直执行,然后等到整棵VDOM树计算完成后,才会交给渲染...
  • 前言React Native 是最近非常火的一个话题,因为它的语法简介,跨平台等特性,赢得了各大平台的青睐,虽然前期是有一些坑。基本概念解释React 是一套可以用简洁的语法高效绘制 DOM 的框架,所谓的“高效”,是因为 ...
  • 对React原理理解

    多人点赞 2022-07-23 17:52:15
    1. VDOM(虚拟dom) ...1.初始化渲染 2.更新时 2.1 render阶段 beginWork completeWork 2.2 commit阶段 before mutation阶段(执行DOM操作前) mutation阶段(执行DOM操作) layout阶段(执行DOM操作后)
  • 浅析React Hooks原理

    2021-08-22 20:59:07
    React Hooks 是 React 16.8 以及之后版本的产物,React Hooks 就是一堆钩子函数,不同的钩子函数提供了不同的功能,React 通过这些钩子函数函数型组件进行增强。Hooks 允许你在不编写 class 的情况下使用状态...
  • // performSyncWorkOnRoot会调用该方法 function workLoopSync() { while (workInProgress !== null) { performUnitOfWork(workInProgress); } } ...// performConcurrentWorkOnRoot会调用该方法 ...
  • React基础原理

    2021-06-26 10:40:48
    React原理揭秘 目标 能够说出React组件的更新机制 能够组件进行性能优化 能够说出虚拟DOM和DIff算法 组件更新机制 setState() 的两个作用 修改state 更新组件 过程:父组件重新渲染时,也会重新渲染子组件...
  • 点击上方蓝字关注程序员成长指北,还可加入「技术交流群」共同进步如今的前端,框架横行,不掌握点框架的知识,出去面试都虚。我比较常用React, 这里就写了一篇 React...
  • 【第1392期】React渲染原理到性能优化(二)-- 更新渲染 黄琼前端早读课今天 前言 没去2018 React Conf的童鞋,别错误今天的。今日早读文章由腾讯IMWeb@黄琼授权分享。 @黄琼,腾讯前端工程师,IMWeb团队...
  • 为什么要用虚拟dom DOM操作很慢,轻微的操作都...React中用JSX语法描述视图,通过babel-loader转译后它们变为React.createElement(…)形式 ,React 17中的 JSX 转换不会将 JSX 转换为 React.createElement,而是自动从

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 13,527
精华内容 5,410
热门标签
关键字:

对react渲染原理的理解