当前位置: 首页 > news >正文

衡水网站建设bdwzjs品牌推广计划书怎么写

衡水网站建设bdwzjs,品牌推广计划书怎么写,株洲seo,西宁做网站最好的公司哪家好hello,这里是潇晨,今天就带着大家一起来手写一个迷你版的hooks,方便大家理解hook在源码中的运行机制,配有图解,保姆级的教程,只求同学一个小小的👍,🐶。 第一步&#xf…

hello,这里是潇晨,今天就带着大家一起来手写一个迷你版的hooks,方便大家理解hook在源码中的运行机制,配有图解,保姆级的教程,只求同学一个小小的👍,🐶。

第一步:引入React和ReactDOM

因为我们要将jsx转变为virtual-dom,这一步分工作就交给babel吧,而jsxbabel进行词法解析之后会形成React.createElement()的调用,而React.createElement()执行之后的返回结果就是jsx对象或者叫virtual-dom

又因为我们要将我们的demo渲染到dom上,所以我们引入ReactDOM

import React from "react";
import ReactDOM from "react-dom";

第二步:我们来写一个小demo

我们定义两个状态countage,在点击的时候触发更新,让它们的值加1。

在源码中useState是保存在一个Dispatcher对象上面的,并且在mountupdate的时候取到的是不同的hooks,所以我们先暂时从Dispatcher上拿到useState,等下在来定义Dispatcher

接下来定义一个schedule函数,每次调用的时候会重新渲染组件。

function App() {let [count, setCount] = Dispatcher.useState(1);let [age, setAge] = Dispatcher.useState(10);return (<><p>Clicked {count} times</p><button onClick={() => setCount(() => count + 1)}> Add count</button><p>Age is {age}</p><button onClick={() => setAge(() => age + 1)}> Add age</button></>);
}function schedule() {    //每次调用会重新渲染组件ReactDOM.render(<App />, document.querySelector("#root"));
}schedule();

第三步:定义Dispatcher

在看这部分前,先来捋清楚fiberhookupdate的关系,看图:

image-20211129105128673

Dispatcher是什么:Dispatcher在源码中就是一个对象,上面存放着各种各样的hooks,在mountupdate的时候会使用过不同的Dispatcher,来看看在源码中Dispatcher是什么样子:

在调用useState之后,会调用一个resolveDispatcher的函数,这个函数调用之后会返回一个dispatcher对象,这个对象上就有useState等钩子。

image-20211126164214374

那我们来看看这个函数做了啥事情,这个函数比较简单,直接从ReactCurrentDispatcher对象上拿到current,然后返回出来的这个current就是dispatcher,那这个ReactCurrentDispatcher又是个啥?别急,继续在源码中来找一下。

image-20211126164903336

在源码中有这样一段代码,如果是在正式环境中,分为两种情况

  1. 如果满足 current === null || current.memoizedState === null,说明我们处于首次渲染的时候,也就是mount的时候,其中current就是我们fiber节点,memoizedState保存了fiberhook,也就是说在应用首次渲染的时候,current fiber是不存在的,我们还没有创造出任何fiber节点,或者存在某些fiber,但是上面没有构建相应的hook,这个时候就可以认为是处于首次渲染的时候,我们取到的是HooksDispatcherOnMount
  2. 如果不满足 current === null || current.memoizedState === null,就说明我们处于更新阶段,也就是update的时候,我们取到的是HooksDispatcherOnUpdate
if (__DEV__) {if (current !== null && current.memoizedState !== null) {ReactCurrentDispatcher.current = HooksDispatcherOnUpdateInDEV;} else if (hookTypesDev !== null) {ReactCurrentDispatcher.current = HooksDispatcherOnMountWithHookTypesInDEV;} else {ReactCurrentDispatcher.current = HooksDispatcherOnMountInDEV;}} else {ReactCurrentDispatcher.current =current === null || current.memoizedState === null? HooksDispatcherOnMount: HooksDispatcherOnUpdate;}

那我们就来看一下这个HooksDispatcherOnMountHooksDispatcherOnUpdate是个什么,好家伙,原来你包含了所有的hooks啊。

const HooksDispatcherOnMount: Dispatcher = {readContext,useCallback: mountCallback,useContext: readContext,useEffect: mountEffect,useImperativeHandle: mountImperativeHandle,useLayoutEffect: mountLayoutEffect,useMemo: mountMemo,useReducer: mountReducer,useRef: mountRef,useState: mountState,useDebugValue: mountDebugValue,useDeferredValue: mountDeferredValue,useTransition: mountTransition,useMutableSource: mountMutableSource,useOpaqueIdentifier: mountOpaqueIdentifier,unstable_isNewReconciler: enableNewReconciler,
};const HooksDispatcherOnUpdate: Dispatcher = {readContext,useCallback: updateCallback,useContext: readContext,useEffect: updateEffect,useImperativeHandle: updateImperativeHandle,useLayoutEffect: updateLayoutEffect,useMemo: updateMemo,useReducer: updateReducer,useRef: updateRef,useState: updateState,useDebugValue: updateDebugValue,useDeferredValue: updateDeferredValue,useTransition: updateTransition,useMutableSource: updateMutableSource,useOpaqueIdentifier: updateOpaqueIdentifier,unstable_isNewReconciler: enableNewReconciler,
};

所以dispatcher就是个对象,里面包含了所有的hooks,在首次渲染和更新的时候拿到的是不同的dispatcher,在调用hooks的时候就会调用到不同的函数,比如如果使用了useState,在mount的时候调用到的就是mountState,在update的时候调用到的就是updateState

image-20211126170906166

现在我们来手写一下dispatcherdispatcher是个对象,对象上存在useState,我们用一个自执行函数来表示,此外还需要用到两个变量和一个常量fiber

  • workInProgressHook表示遍历到的hook(因为hook会保存在链表上,需要遍历链表计算hook上保存的状态)
  • 为了简单起见,定义一个isMount=true表示mount的时候,在update的时候将它设置成false
  • 为简单起见,fiber就定义成一个对象,memoizedState表示这个fiber节点上存放的hook链表,stateNode就是第二步的demo。

相关参考视频讲解:进入学习

let workInProgressHook;//当前工作中的hook
let isMount = true;//是否时mount时const fiber = {//fiber节点memoizedState: null,//hook链表stateNode: App
};const Dispatcher = (() => {//Dispatcher对象function useState(){//。。。}return {useState};
})();

在定义useState之前,首先来看看hookupdate的数据结构

hook:
  • queue:上面有pending属性,pending也是一条环状链表,上面存放了未被更新的update,也就是说这些update会以next指针连接成环状链表。
  • memoizedState表示当前的状态
  • next:指向下一个hook,形成一条链表
 const hook = {//构建hookqueue: {pending: null//未执行的update链表},memoizedState: null,//当前statenext: null//下一个hook};
update:
  • action:是出发更新的函数
  • next:连接下一个update,形成一条环状链表
 const update = {//构建updateaction,next: null};

那接下来定义useState吧,分三个部分:

  • 创建hook或取到hook
    1. mount的时候:调用mountWorkInProgressHook创建一个初始的hook,赋值useState传进来的初始值initialState
    2. update的时候:调用updateWorkInProgressHook,拿到当前正在工作的hook
  • 计算hook上未更新的状态:遍历hook上的pending链表,调用链表节点上的action函数,生成一个新的状态,然后更新hook上的状态。
  • 返回新的状态和dispatchAction传入queue参数
function useState(initialState) {//第1步:创建hook或取到hooklet hook;if (isMount) {hook = mountWorkInProgressHook();hook.memoizedState = initialState;//初始状态} else {hook = updateWorkInProgressHook();}//第2步:计算hook上未更新的状态let baseState = hook.memoizedState;//初始状态if (hook.queue.pending) {let firstUpdate = hook.queue.pending.next;//第一个updatedo {const action = firstUpdate.action;baseState = action(baseState);//调用action计算新的状态firstUpdate = firstUpdate.next;//通过update的action计算state} while (firstUpdate !== hook.queue.pending);//当链表还没遍历完时 进行循环hook.queue.pending = null;//重置update链表}hook.memoizedState = baseState;//赋值新的state//第3步:返回新的状态和dispatchAction传入queue参数return [baseState, dispatchAction.bind(null, hook.queue)];//useState的返回}

接下来定义mountWorkInProgressHookupdateWorkInProgressHook这两个函数

  • mountWorkInProgressHook:在mount的时候调用,新创建一个hook对象,
    1. 如果当前fiber不存在memoizedState,那当前hook就是这个fiber上的第一个hook,将hook赋值给fiber.memoizedState
    2. 如果当前fiber存在memoizedState,那将当前hook接在workInProgressHook.next后面。
    3. 将当前hook赋值给workInProgressHook
  • updateWorkInProgressHook:在update的时候调用,返回当前的hook,也就是workInProgressHook,并且将workInProgressHook指向hook链表的下一个。
function mountWorkInProgressHook() {//mount时调用const hook = {//构建hookqueue: {pending: null//未执行的update链表},memoizedState: null,//当前statenext: null//下一个hook};if (!fiber.memoizedState) {fiber.memoizedState = hook;//第一个hook的话直接赋值给fiber.memoizedState} else {workInProgressHook.next = hook;//不是第一个的话就加在上一个hook的后面,形成链表}workInProgressHook = hook;//记录当前工作的hookreturn workInProgressHook;}function updateWorkInProgressHook() {//update时调用let curHook = workInProgressHook;workInProgressHook = workInProgressHook.next;//下一个hookreturn curHook;
}

第四步:定义dispatchAction

  • 创建update,挂载载queue.pending

    1. 如果之前queue.pending不存在,那创建的这个update就是第一个,则update.next = update
    2. 如果之前queue.pending存在,则将创建的这个update加入queue.pending的环状链表中

    1

  • isMount=false,并且赋值workInProgressHook,调用schedule进行更新渲染

function dispatchAction(queue, action) {//触发更新const update = {//构建updateaction,next: null};if (queue.pending === null) {update.next = update;//update的环状链表} else {update.next = queue.pending.next;//新的update的next指向前一个updatequeue.pending.next = update;//前一个update的next指向新的update}queue.pending = update;//更新queue.pendingisMount = false;//标志mount结束workInProgressHook = fiber.memoizedState;//更新workInProgressHookschedule();//调度更新
}

最终代码

import React from "react";
import ReactDOM from "react-dom";let workInProgressHook;//当前工作中的hook
let isMount = true;//是否时mount时const fiber = {//fiber节点memoizedState: null,//hook链表stateNode: App//dom
};const Dispatcher = (() => {//Dispatcher对象function mountWorkInProgressHook() {//mount时调用const hook = {//构建hookqueue: {pending: null//未执行的update链表},memoizedState: null,//当前statenext: null//下一个hook};if (!fiber.memoizedState) {fiber.memoizedState = hook;//第一个hook的话直接赋值给fiber.memoizedState} else {workInProgressHook.next = hook;//不是第一个的话就加在上一个hook的后面,形成链表}workInProgressHook = hook;//记录当前工作的hookreturn workInProgressHook;}function updateWorkInProgressHook() {//update时调用let curHook = workInProgressHook;workInProgressHook = workInProgressHook.next;//下一个hookreturn curHook;}function useState(initialState) {let hook;if (isMount) {hook = mountWorkInProgressHook();hook.memoizedState = initialState;//初始状态} else {hook = updateWorkInProgressHook();}let baseState = hook.memoizedState;//初始状态if (hook.queue.pending) {let firstUpdate = hook.queue.pending.next;//第一个updatedo {const action = firstUpdate.action;baseState = action(baseState);firstUpdate = firstUpdate.next;//循环update链表} while (firstUpdate !== hook.queue.pending);//通过update的action计算statehook.queue.pending = null;//重置update链表}hook.memoizedState = baseState;//赋值新的statereturn [baseState, dispatchAction.bind(null, hook.queue)];//useState的返回}return {useState};
})();function dispatchAction(queue, action) {//触发更新const update = {//构建updateaction,next: null};if (queue.pending === null) {update.next = update;//update的环状链表} else {update.next = queue.pending.next;//新的update的next指向前一个updatequeue.pending.next = update;//前一个update的next指向新的update}queue.pending = update;//更新queue.pendingisMount = false;//标志mount结束workInProgressHook = fiber.memoizedState;//更新workInProgressHookschedule();//调度更新
}function App() {let [count, setCount] = Dispatcher.useState(1);let [age, setAge] = Dispatcher.useState(10);return (<><p>Clicked {count} times</p><button onClick={() => setCount(() => count + 1)}> Add count</button><p>Age is {age}</p><button onClick={() => setAge(() => age + 1)}> Add age</button></>);
}function schedule() {ReactDOM.render(<App />, document.querySelector("#root"));
}schedule();

预览效果:https://codesandbox.io/s/custom-hook-tyf19?file=/src/index.js

http://www.mmbaike.com/news/74589.html

相关文章:

  • 设置网站的关键词seo搜索引擎优化推广专员
  • 网站排名优化如何做网络销售新手入门
  • 使用html作为wordpress登录seo双标题软件
  • 有域名后怎样做网站优化网站哪个好
  • 湘西网站建设公司seo建站平台哪家好
  • 关键词优化案例优化大师官方正版下载
  • 网站文字变白色代码怎么做seo培训教程视频
  • 做纺织都有那些好网站搜索引擎优化人员优化
  • 网站制作公司教你怎么制作网站哈尔滨百度推广联系人
  • 网站用什么框架做指数基金有哪些
  • 深圳网站和app建设电脑版百度
  • 地方旅游网站模板常用的网络推广手段有哪些
  • 免备案空间网站备案竞价
  • 河南省路桥建设集团网站网络营销推广策略
  • 广州市增城建设局网站seo优化方案案例
  • 表单网站怎么做seo公司如何建立网站
  • 成都大型网站建设全国知名网站排名
  • 做电影网站用什么程序企业网站免费制作
  • 汕头自助建站模板百度广告推广价格
  • 网站制作需要什么人员企业推广平台排行榜
  • 网站和网页的区别在于互联网项目推广平台有哪些
  • 做简历的网站百度信息流怎么收费
  • 下载手机最新版app济南网站优化培训
  • 高端建站的公司2022年明星百度指数排行
  • 企业信用信息网查询系统官网网站优化排名怎么做
  • 宁波做网站公司魔贝课凡seo
  • 站酷素材seo网站排名优化教程
  • 仿大学网站网页代码如何开网站呢
  • 宝马itms做课网站游戏推广引流
  • 网站模板50元什么是网络软文营销