We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
感谢 yck: 剖析 React 源码解析,本篇文章是在读完他的文章的基础上,将他的文章进行拆解和加工,加入我自己的一下理解和例子,便于大家理解。觉得yck写的真的很棒 。React 版本为 16.8.6,关于源码的阅读,可以移步到yck react源码解析
本文永久有效链接: react解析: render的中的update(四)
上一章节说到,不存在root数据节点,即通过createFiberRoot 函数创建FiberRoot,FiberRoot对象是整个React应用的起点,同时也记录了整个React应用更新过程中的各种信息。
FiberRoot
下面将要聊到的就是,当root呗创建后,还会发生什么👇👇
下面衔接上一部分内容,不懂得可以查看上一章节。
yck: ReactDOM 源码 554行 legacyRenderSubtreeIntoContainer
function legacyRenderSubtreeIntoContainer( parentComponent: ?React$Component<any, any>, children: ReactNodeList, container: DOMContainer, forceHydrate: boolean, callback: ?Function, ) { // 初始化时,container 肯定没有 _reactRootContainer属性 let root: Root = (container._reactRootContainer: any); if (!root) { // 省略创建root部分 unbatchedUpdates(() => { if (parentComponent != null) { root.legacy_renderSubtreeIntoContainer( parentComponent, children, callback, ); } else { root.render(children, callback); } }); } }
在root刚刚被创建时,parentComponent一般都为null;
parentComponent
unbatchedUpdates函数在这里作用是:告知React内部不进行批量更新,即不用将多个setState合并为一个; (setState在后面的章节我们将会说到)
unbatchedUpdates
那么这里实际调用的就是root.render函数,root是ReactRoot实例对象,即调用 root.render函数 == ReactRoot.prototype.render函数。
root.render函数 == ReactRoot.prototype.render函数
yck: ReactRoot 源码 377行 ReactRoot.prototype.render
ReactRoot.prototype.render = function( children: ReactNodeList, callback: ?() => mixed, ): Work { // 这里指 FiberRoot const root = this._internalRoot; const work = new ReactWork(); callback = callback === undefined ? null : callback; // 如果有 callback,就 push 进 work 中的数组 if (callback !== null) { work.then(callback); } // work._onCommit 就是用于执行所有回调函数的 updateContainer(children, root, null, work._onCommit); return work; };
函数中的参数children即是ReactElement节点对象,callback为回调函数。ReactWork实例对象的主要作用就是维护一个回调数组,可查看yck: ReactWork 源码 327行,如果传入参数中存在callback,就将其挂载ReactWork实例对象中;
children
callback
ReactWork
下面来看看updateContainer函数会做什么。
yck: ReactFiberReconciler 源码 284行 updateContainer
export function updateContainer( element: ReactNodeList, container: OpaqueRoot, parentComponent: ?React$Component<any, any>, callback: ?Function, ): ExpirationTime { const current = container.current; // 计算时间 const currentTime = requestCurrentTime(); // expirationTime 代表优先级,数字越大优先级越高 // sync 的数字是最大的,所以优先级也是最高的 const expirationTime = computeExpirationForFiber(currentTime, current); return updateContainerAtExpirationTime( element, container, parentComponent, expirationTime, callback, ); }
container.current即是从FiberRoot中取出RootFiber对象,currentTime就是当前距离React应用初始化的时间。 **expirationTime字面意思就是过期时间,后面我会专门花一章的时间来介绍这两个时间,这两个时间也是React应用任务调度的重点。
container.current
RootFiber
currentTime
expirationTime
updateContainerAtExpirationTime函数实际调用的就是scheduleRootUpdate函数,下面来说一下scheduleRootUpdate函数的作用。
scheduleRootUpdate
yck: ReactFiberReconciler 源码 114行 scheduleRootUpdate
function scheduleRootUpdate( current: Fiber, element: ReactNodeList, expirationTime: ExpirationTime, callback: ?Function, ) { // 创建一个 update,就是内部有几个属性的对象 const update = createUpdate(expirationTime); update.payload = {element}; // render中的回调函数 callback = callback === undefined ? null : callback; if (callback !== null) { update.callback = callback; } flushPassiveEffects(); // 把 update 入队,内部就是一些创建或者获取 queue(链表结构),然后给链表添加一个节点的操作 enqueueUpdate(current, update); scheduleWork(current, expirationTime); return expirationTime; }
下面就是update对象其中的属性:
// update对象属性 export type Update<State> = { // 更新的过期时间 expirationTime: ExpirationTime, // export const UpdateState = 0; // export const ReplaceState = 1; // export const ForceUpdate = 2; // export const CaptureUpdate = 3; // 指定更新的类型,值为以上几种 tag: 0 | 1 | 2 | 3, // 更新内容,比如`setState`接收的第一个参数 payload: any, // 对应的回调,`setState`,`render`都有 callback: (() => mixed) | null, // 指向下一个更新 next: Update<State> | null, // 指向下一个`side effect` nextEffect: Update<State> | null, };
udate对象会被插入到React应用维护的任务队列中,不管你是setState还是ReactDOM.render造成的 React应用 更新都是如此。这个函数核心作用就是创建或者获取一个队列,然后把 update 对象插入队列进行更新。scheduleWork函数就是任务调度的东西了。
scheduleWork
更多内容:
react解析: React.createElement(一)
react解析: React.Children(二)
react解析: render的FiberRoot(三)
参考:
yck: 剖剖析 React 源码
Jokcy 的 《React 源码解析》: react.jokcy.me/
ps: 顺便推一下自己的个人公众号:Yopai,有兴趣的可以关注,每周不定期更新,分享可以增加世界的快乐
The text was updated successfully, but these errors were encountered:
HerryLo
No branches or pull requests
上一章节说到,不存在root数据节点,即通过createFiberRoot 函数创建FiberRoot,
FiberRoot
对象是整个React应用的起点,同时也记录了整个React应用更新过程中的各种信息。下面将要聊到的就是,当root呗创建后,还会发生什么👇👇
legacyRenderSubtreeIntoContainer 函数
下面衔接上一部分内容,不懂得可以查看上一章节。
在root刚刚被创建时,
parentComponent
一般都为null;unbatchedUpdates
函数在这里作用是:告知React内部不进行批量更新,即不用将多个setState合并为一个;(setState在后面的章节我们将会说到)
那么这里实际调用的就是root.render函数,root是ReactRoot实例对象,即调用
root.render函数 == ReactRoot.prototype.render函数
。ReactRoot.prototype.render 函数
函数中的参数
children
即是ReactElement节点对象,callback
为回调函数。ReactWork
实例对象的主要作用就是维护一个回调数组,可查看yck: ReactWork 源码 327行,如果传入参数中存在callback,就将其挂载ReactWork
实例对象中;下面来看看updateContainer函数会做什么。
updateContainer 函数
container.current
即是从FiberRoot中取出RootFiber
对象,currentTime
就是当前距离React应用初始化的时间。 **expirationTime
字面意思就是过期时间,后面我会专门花一章的时间来介绍这两个时间,这两个时间也是React应用任务调度的重点。scheduleRootUpdate函数
updateContainerAtExpirationTime函数实际调用的就是
scheduleRootUpdate
函数,下面来说一下scheduleRootUpdate
函数的作用。下面就是update对象其中的属性:
udate对象会被插入到React应用维护的任务队列中,不管你是setState还是ReactDOM.render造成的 React应用 更新都是如此。这个函数核心作用就是创建或者获取一个队列,然后把 update 对象插入队列进行更新。
scheduleWork
函数就是任务调度的东西了。更多内容:
react解析: React.createElement(一)
react解析: React.Children(二)
react解析: render的FiberRoot(三)
参考:
yck: 剖剖析 React 源码
Jokcy 的 《React 源码解析》: react.jokcy.me/
ps: 顺便推一下自己的个人公众号:Yopai,有兴趣的可以关注,每周不定期更新,分享可以增加世界的快乐
The text was updated successfully, but these errors were encountered: