首页 > 其他分享 >完整实现React day10

完整实现React day10

时间:2023-04-28 17:23:54浏览次数:47  
标签:const Hook workInProgressHook memoizedState React hook 完整 day10 null

update流程与mount流程的区别。

对于beginWork

  • 需要处理ChildDeletion的情况
  • 需要处理节点移动的情况(abc -> bca)

对于completeWork

  • 需要处理HostText内容更新的情况
  • 需要处理HostComponent属性变化的情况

对于commitWork

  • 对于ChildDeletion,需要遍历被删除的子树
  • 对于Update,需要更新文本内容

对于useState

  • 实现相对于mountStateupdateState

beginWork流程

本节课仅处理单一节点,所以省去了「节点移动」的情况。我们需要处理:

  • singleElement
  • singleTextNode

处理流程为:

  1. 比较是否可以复用current fiber
    1. 比较key,如果key不同,不能复用
    2. 比较type,如果type不同,不能复用
    3. 如果keytype都相同,则可复用
  2. 不能复用,则创建新的(同mount流程),可以复用则复用旧的

注意:对于同一个fiberNode,即使反复更新,currentwip这两个fiberNode会重复使用

completeWork流程

主要处理「标记Update」的情况,本节课我们处理HostText内容更新的情况。

commitWork流程

对于标记ChildDeletion的子树,由于子树中:

  • 对于FC,需要处理useEffect unmout执行、解绑ref
  • 对于HostComponent,需要解绑ref
  • 对于子树的根HostComponent,需要移除DOM

所以需要实现「遍历ChildDeletion子树」的流程

对于useState

需要实现:

  • 针对update时的dispatcher
  • 实现对标mountWorkInProgresHookupdateWorkInProgresHook
  • 实现updateState「计算新state的逻辑」

其中updateWorkInProgresHook的实现需要考虑的问题:

  • hook数据从哪来?
  • 交互阶段触发的更新
    import { useState } from 'react';
    import { Dispatch } from 'react/src/currentDispatcher';
    import { Dispatcher } from 'react/src/currentDispatcher';
    import internals from 'shared/internals';
    import { Action } from 'shared/ReactTypes';
    import { FiberNode } from './fiber';
    import {
        createUpdate,
        createUpdateQueue,
        enqueueUpdate,
        processUpdateQueue,
        UpdateQueue
    } from './updateQueue';
    import { scheduleUpdateOnFiber } from './workLoop';
    
    let currentlyRenderingFiber: FiberNode | null = null;
    let workInProgressHook: Hook | null = null;
    let currentHook: Hook | null = null;
    
    const { currentDispatcher } = internals;
    interface Hook {
        memoizedState: any;
        updateQueue: unknown;
        next: Hook | null;
    }
    
    export function renderWithHooks(wip: FiberNode) {
        // 赋值操作
        currentlyRenderingFiber = wip;
        // 重置 hooks链表
        wip.memoizedState = null;
    
        const current = wip.alternate;
    
        if (current !== null) {
            // update
            currentDispatcher.current = HooksDispatcherOnUpdate;
        } else {
            // mount
            currentDispatcher.current = HooksDispatcherOnMount;
        }
    
        const Component = wip.type;
        const props = wip.pendingProps;
        // FC render
        const children = Component(props);
    
        // 重置操作
        currentlyRenderingFiber = null;
        workInProgressHook = null;
        currentHook = null;
        return children;
    }
    
    const HooksDispatcherOnMount: Dispatcher = {
        useState: mountState
    };
    
    const HooksDispatcherOnUpdate: Dispatcher = {
        useState: updateState
    };
    
    function updateState<State>(): [State, Dispatch<State>] {
        // 找到当前useState对应的hook数据
        const hook = updateWorkInProgresHook();
    
        // 计算新state的逻辑
        const queue = hook.updateQueue as UpdateQueue<State>;
        const pending = queue.shared.pending;
    
        if (pending !== null) {
            const { memoizedState } = processUpdateQueue(hook.memoizedState, pending);
            hook.memoizedState = memoizedState;
        }
    
        return [hook.memoizedState, queue.dispatch as Dispatch<State>];
    }
    
    function updateWorkInProgresHook(): Hook {
        // TODO render阶段触发的更新
        let nextCurrentHook: Hook | null;
    
        if (currentHook === null) {
            // 这是这个FC update时的第一个hook
            const current = currentlyRenderingFiber?.alternate;
            if (current !== null) {
                nextCurrentHook = current?.memoizedState;
            } else {
                // mount
                nextCurrentHook = null;
            }
        } else {
            // 这个FC update时 后续的hook
            nextCurrentHook = currentHook.next;
        }
    
        if (nextCurrentHook === null) {
            throw new Error(
                `组件${currentlyRenderingFiber?.type}本次执行时的Hook比上次执行时多`
            );
        }
    
        currentHook = nextCurrentHook as Hook;
        const newHook: Hook = {
            memoizedState: currentHook.memoizedState,
            updateQueue: currentHook.updateQueue,
            next: null
        };
        if (workInProgressHook === null) {
            // mount时 第一个hook
            if (currentlyRenderingFiber === null) {
                throw new Error('请在函数组件内调用hook');
            } else {
                workInProgressHook = newHook;
                currentlyRenderingFiber.memoizedState = workInProgressHook;
            }
        } else {
            // mount时 后续的hook
            workInProgressHook.next = newHook;
            workInProgressHook = newHook;
        }
        return workInProgressHook;
    }
    
    function mountState<State>(
        initialState: (() => State) | State
    ): [State, Dispatch<State>] {
        // 找到当前useState对应的hook数据
        const hook = mountWorkInProgresHook();
        let memoizedState;
        if (initialState instanceof Function) {
            memoizedState = initialState();
        } else {
            memoizedState = initialState;
        }
        const queue = createUpdateQueue<State>();
        hook.updateQueue = queue;
        hook.memoizedState = memoizedState;
    
        // @ts-ignore
        const dispatch = dispatchSetState.bind(null, currentlyRenderingFiber, queue);
        queue.dispatch = dispatch;
        return [memoizedState, dispatch];
    }
    
    function dispatchSetState<State>(
        fiber: FiberNode,
        updateQueue: UpdateQueue<State>,
        action: Action<State>
    ) {
        const update = createUpdate(action);
        enqueueUpdate(updateQueue, update);
        scheduleUpdateOnFiber(fiber);
    }
    
    function mountWorkInProgresHook(): Hook {
        const hook: Hook = {
            memoizedState: null,
            updateQueue: null,
            next: null
        };
        if (workInProgressHook === null) {
            // mount时 第一个hook
            if (currentlyRenderingFiber === null) {
                throw new Error('请在函数组件内调用hook');
            } else {
                workInProgressHook = hook;
                currentlyRenderingFiber.memoizedState = workInProgressHook;
            }
        } else {
            // mount时 后续的hook
            workInProgressHook.next = hook;
            workInProgressHook = hook;
        }
        return workInProgressHook;
    }

     

标签:const,Hook,workInProgressHook,memoizedState,React,hook,完整,day10,null
From: https://www.cnblogs.com/libertylhy/p/17362718.html

相关文章

  • 老杜Vue实战教程完整版笔记(5)Vuex
    接上篇文章,分享动力节点老杜全新版Vue教程笔记学习の地止:https://www.bilibili.com/video/BV17h41137i45Vuex5.1vuex概述vuex是实现数据集中式状态管理的插件。数据由vuex统一管理。其它组件都去使用vuex中的数据。只要有其中一个组件去修改了这个共享的数据,其它组件会同......
  • react- hooks 之 useMemo
    1.传入数组的变量需要在使用前进行定义,const[issueType,setIssueType]=useState('1');constissueDisable=useMemo(()=>{console.log('issueType改变啦',issueType,dataSource,haveDetaildataSource);},[issueType,dataSource,haveDetailda......
  • React中的另一种状态管理方案Valtio
    React中的状态管理是开发人员需要解决的问题。总有一些新库给你选择,而选择合适的库可能是一项困难的工作状态管理一直是React中开发人员需要解决的问题,如何有条理的组织数据,如何快速的在项目中集成,这些都是我们做项目时选择技术的标准。Redux一直是我们react项目中不二的状态管......
  • [React-Native]样式和布局
    一、基本样式(1)内联样式在组件里面定义样式<Textstyle={{color:'orange',fontSize:20}}>小字号内联样式</Text>(2)外联样式在组件里指向外面的样式<Textstyle={[styles.orange,styles.bigFontSize]}>大字号外联样式</Text>(3)样式具有覆盖性如果定义相同属性的样式,后面会覆......
  • Vue3中ref和reactive的对比
     先说ref()和reactive()Vue3这两个API作用是相似的,只不过ref()是针对变量的响应式包装,而reactive()是针对对象的响应式包装。 ref()和reactive()对比API说明目标ref()传入一个值,返回一个响应式的变量变量reactive()返回一个对象的响应式代理。通过Proxy包......
  • 汇总|React Native 开发工具一赏
    传统的开发中,按照平台划分为iOS,Android,Windows和Mac。其中,随着移动设备的使用移动端应用的开发也越来越多。传统上iOS应用使用Xcode工具、Objective-C和Swift语言进行开发,Android应用使用AndroidStudio工具、Java和kotlin语言进行开发。随着开发的普及......
  • react的基本:条件渲染
    importreactDomfrom"react-dom"//条件渲染ifelseletloading=false//写一个函数用于加载constloadData=()=>{if(loading){return<div>数据加载中</div>}else{return<div>数据加载完成,此处直接显示数据</div>}......
  • react的基本使用
    //导入react和react-dom包importreactfrom'react'importreactDomfrom'react-dom'//console.log(react)//console.log(reactDom)//创建react元素//参数1.元素2.属性【没有就写null】3.元素子节点//react创建元素并返回consth1=react.crea......
  • 为什么以及什么时候 React 会渲染一个组件
    组件显示到屏幕之前,其必须被React渲染。在您触发渲染后,React会调用您的组件来确定要在屏幕上显示的内容。“渲染中”即React在调用您的组件。在进行初次渲染时,React会调用根组件。对于后续的渲染,React会调用内部状态更新触发了渲染的函数组件。这个过程是递归......
  • react 更新状态中的对象
    State可以保存任何类型的JavaScript值,包括对象。但是你不应该直接改变你在React状态下持有的对象。相反,当你想更新一个对象时,你需要创建一个新对象(或复制一个现有对象),然后设置状态以使用该副本。const[position,setPosition]=useState({x:0,y:0});从技术上讲,可......