Git Product home page Git Product logo

just-react's Issues

render阶段,beginWork和completeWork

在最新的master代码中,三个月之前有一次更新,移除了effectTag

const deletions = returnFiber.deletions;
    if (deletions === null) {
      returnFiber.deletions = [childToDelete];
      returnFiber.flags |= Deletion;
    } else {
      deletions.push(childToDelete);
    }

使用了flags进行判断

react version effectList

架构篇/completeWork/effectList章节, react 17.0.3版本 completeUnitOfWork里面并没有effectList的代码逻辑,。老卡,文档得更新了

卡卡颂老师

用你在码云上打包,yarn link到创建项目里之后 跑起来就报各种依赖找不到为啥啊。。。

beginWork和completeWork的疑问

https://react.iamkasong.com/process/reconciler.html#%E4%BE%8B%E5%AD%90

看图上所示的每个component都会执行到beginWork和completeWork,但实际上并不是这样的
completeWork只有在child没有的时候才会执行,然后找到fiber树上一个有slibing的组件执行beginWork
这样并不是所有组件都会有completeWork

尝试打印了下自己的代码大概如下

beginWork App
scheduler.development.js:468 beginWork RecoilRoot
scheduler.development.js:468 beginWork RecoilRoot_INTERNAL
2scheduler.development.js:468 beginWork undefined
scheduler.development.js:468 beginWork Batcher
scheduler.development.js:468 completeUnitOfWork Batcher
scheduler.development.js:468 beginWork GlobalThemeProvider
scheduler.development.js:468 beginWork undefined
scheduler.development.js:468 beginWork ThemeProvider
2scheduler.development.js:468 beginWork undefined
scheduler.development.js:468 beginWork CssBaseline
scheduler.development.js:468 beginWork LanguageProvider
scheduler.development.js:468 beginWork undefined
scheduler.development.js:468 beginWork ThemeProvider
scheduler.development.js:468 beginWork undefined
scheduler.development.js:468 beginWork Initer
scheduler.development.js:468 beginWork SnackbarProvider
scheduler.development.js:468 beginWork undefined
scheduler.development.js:468 beginWork AxiosIniter
scheduler.development.js:468 completeUnitOfWork AxiosIniter
scheduler.development.js:468 beginWork null
scheduler.development.js:468 completeUnitOfWork null

关于极简react的Demo的问题

// 环状单向链表操作
  if (queue.pending === null) {
    update.next = update;
  } else {
    update.next = queue.pending.next;
    queue.pending.next = update;
  }
  queue.pending = update;

既然queue.pending保存着上个update,next指向自己,是否也可写为

...
  } else {
    update.next = queue.pending;
    queue.pending.next = update;
  }
...

rootFiberNode 是不是改成 fiberRootNode 会比较好?

原因有以下几点:

  • 因为是由 FiberRootNode 实例化而来

  • rootFiberNode 和 rootFiber 意思感觉有点相近,容易混淆

  • fiberRootNode 语义更符合,表示 fiber 树的根节点,而 rootFiberNode 则表示根 fiber 节点

  • 源码中叫 fiberRoot

如果你觉得需要改的话,我可以贡献一个 PR 😆

请问:useEffect在commit的layout阶段执行的原因?

image
楼主你好:
在layout阶段可以执行useEffect的调用和销毁,一般不是在before mutation执行useEffect的回调,在delete某个节点时执行useEffect执行销毁。
如果在layout执行其调用和销毁,不是清楚了before mutation中执行的回调?
此外我的这个代码在页面渲染完成,也就是layout并没有发现页面的标题发生了改变?
useEffect(() => { return () => { document.title='???' } }, [])
谢谢帮忙解答💕

React15架构描述一段,关于递归缺点的问题

在React15架构的最后一段,描述递归更新的缺点描述时,举的例子和我的理解有些出入,这里想提出来讨论一下。

我记得v15的stack的问题在于,节点一层套一层,必须同步递归处理要更新的节点和所有子节点,这样一来如果超过16ms,就会造成用户操作失去响应。更新过程中如果要支持其他异步操作,保存现场的开销会很大。而fiber用了链表和双缓存的结构来改进。

下面给出的例子,是出现在替换真实节点的时候,那就体现不了stack的上述缺点。

我认为真实节点的更新,在v16里还是“同步”操作,不会更新到一半,去处理其他异步任务。如果这里用户看到了未更新的节点,那在v16里应该也是一样的。

How should the two different components be compared in page `/preparation/idea.html`?

The two component demos in page /preparation/idea.html of vue and react are absolutely different. How should they be compared in that case?

What a react component similar to the vue component should look like the following:

// react jsx
<ul>
  <li>0</li>
  <li>{ name }</li>
  <li>2</li>
  <li>3</li>
</ul>

And. What a vue component similar to the react component should look like the following:

<!-- vue template -->
<template>
  <ul>
    <li v-for="(name, i) in data">{{ i !== 1 ? i : name }}</li>
  </ul>
</template>

Looking forward to reply! thx :-)

在create-react-app创建的项目使用yarn link, yarn start 报错

/Users/xxxx/resource/project/front-end/github/react/packages/react/index.js:11
export type StatelessFunctionalComponent<
^^^^^^

SyntaxError: Unexpected token export
at Module._compile (internal/modules/cjs/loader.js:721:23)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Module.require (internal/modules/cjs/loader.js:690:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object. (/Users/huanghao/resource/project/front-end/demo/a-react-demo/node_modules/react-scripts/scripts/start.js:52:15)
at Module._compile (internal/modules/cjs/loader.js:776:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

coomitRoot阶段layout阶段阐述存疑

beforeMutation阶段
就讲过,before mutation阶段在scheduleCallback中调度flushPassiveEffects

而在layout阶段

对于FunctionComponent及相关类型,他会调用useLayoutEffect hook的回调函数,调度useEffect的销毁与回调函数

光从以上两段论述中,是不是可以说 useEffect的相关回调在beforeMutation和layout两个阶段都被调用了啊

17.0.2源码我大概看了下 对应位置的代码似乎变成了:

case FunctionComponent:
    case ForwardRef:
    case SimpleMemoComponent:
    case Block:
      {
        // At this point layout effects have already been destroyed (during mutation phase).
        // This is done to prevent sibling component effects from interfering with each other,
        // e.g. a destroy function in one component should never override a ref set
        // by a create function in another component during the same commit.
        {
          commitHookEffectListMount(Layout | HasEffect, finishedWork);
        }

        schedulePassiveEffects(finishedWork);
        return;
      }

关于 Fiber 和 React Virtual DOM 的概念

在看卡老师的电子书的 render阶段章节https://kasong.gitee.io/just-react/process/fiber.html,发现有一处地方好像和官方文档https://reactjs.org/docs/faq-internals.html有点点不一样:

1、卡老师的书中提到:“虚拟DOM在React中有个正式的称呼——Fiber。 ...... 我们会逐渐用 Fiber 来取代 React 16 虚拟DOM 这一称呼”:

image

2、但是官方文档提到:React 的“虚拟DOM”的实现其实包含了 React Element 和 fiber 两者:

image

打包react、scheduler、react-dom三个包为dev环境可以使用的cjs包

执行yarn build react,react-dom,scheduler --type=NODE 时
报Cannot find module 'react-server-dom-webpack/node-loader'

node: '12.16.2',
v8: '7.8.279.23-node.34',
uv: '1.34.2',
zlib: '1.2.11',
brotli: '1.0.7',
ares: '1.15.0',
modules: '72',
nghttp2: '1.40.0',
napi: '5',
llhttp: '2.0.4',
http_parser: '2.9.3',
openssl: '1.1.1e',
cldr: '36.0',
icu: '65.1',
tz: '2019c',
unicode: '12.1'

Scheduler队列设计疑问

目前React关于Scheduler设计存在两个队列:保存未就绪任务timerQueue和保存已就绪任务taskQueue,每次调度时会判断未就绪任务是否已就绪,是加入到taskQueue。但是从过期时间的角度来看,貌似这种设计有点冗余,如果把延迟的任务也转换为过期时间,然后放在统一的任务队列(假设是taskQueue),统一走最小堆的维护和取值策略,那是不是也能满足需求,并且逻辑上也更简单点

React 新手🥬小白的苦恼

作为一个从 Vue 技术栈转入的同学,我深感 React 社区文化的浓厚(潜台词:TMD 工程环境真难配)
大佬可否出一期文章,教教大家怎么样构建一个更系统、更工程化一点的 React 项目,让大家用起来学起来没那么懵 😭

before mutation阶段文档和源码不一致

如题,commit的before mutation阶段,源码分为commitBeforeMutationEffects_begin,commitBeforeMutationEffects_complete,使用subtree的方式进行遍历。除此之外,flushPassiveEffects的遍历方式也有一定变化,大佬有时间可否更新下?

function commitBeforeMutationEffects_begin() {
  while (nextEffect !== null) {
    var fiber = nextEffect; // TODO: Should wrap this in flags check, too, as optimization

    var deletions = fiber.deletions;

    if (deletions !== null) {
      for (var i = 0; i < deletions.length; i++) {
        var deletion = deletions[i];
        commitBeforeMutationEffectsDeletion(deletion);
      }
    }

    var child = fiber.child;

    if ((fiber.subtreeFlags & BeforeMutationMask) !== NoFlags && child !== null) {
      ensureCorrectReturnPointer(child, fiber);
      nextEffect = child;
    } else {
      commitBeforeMutationEffects_complete();
    }
  }
}

function commitBeforeMutationEffects_complete() {
  while (nextEffect !== null) {
    var fiber = nextEffect;

    {
      setCurrentFiber(fiber);
      invokeGuardedCallback(null, commitBeforeMutationEffectsOnFiber, null, fiber);

      if (hasCaughtError()) {
        var error = clearCaughtError();
        captureCommitPhaseError(fiber, fiber.return, error);
      }

      resetCurrentFiber();
    }

    var sibling = fiber.sibling;

    if (sibling !== null) {
      ensureCorrectReturnPointer(sibling, fiber.return);
      nextEffect = sibling;
      return;
    }

    nextEffect = fiber.return;
  }
}

多节点 Diff 的时候, abcd -> acbd 的情况要怎么处理?

新 acbd
旧 abcd

按照分析来说,
第一轮遍历 确定 a 可以复用,并在遍历 第二个元素 c 的时候 发现 key 不同,停止了遍历 进入了 第二轮遍历。

此时:
old bcd
new cbd
开始 第二轮遍历 -> c
lastPlacedIndex = 0
oldIndex = 2
oldIndex >= lastPlacedIndex
不移动且 lastPlacedIndex = oldIndex = 2

-> b
oldIndex = 1
oldIndex < lastPlacedIndex
标记移动 lastPlacedIndex = 2 不变

-> d
oldIndex = 3
oldIndex >= lastPlacedIndex
不移动且 lastPlacedIndex = oldIndex = 3

至此遍历完毕。

只有 b 元素被标记移动, 但是没有说要怎么移动, 移动到最右边吗。
但是实际中,也只有移动到 c 的后面

关于理念篇-新的React架构

image
“在阐述新React架构特点时,Scheduler到Reconciler的工作时说如果有更高优任务需要先更新或者当前帧的时间没有剩余时间,步骤会中断,renderer后用户也不会看见更新不完全的DOM”。
这种描述是不是有问题? 如果有更高优先级的任务需要先更新,会中断去redenerer高优先级的任务,那么当前的任务在当前帧实际上没有更新,那用户看到的是依然是更新不完全的DOM界面,只能说同一优先级的任务会一起更新到同一帧,不同优先级不保证 ,这样理解对不对?

增加一个码云的国内镜像作为源码的拉取地址

首先感谢大佬的教程,详细,对新手真的太友好了,如果出书了我马上下单。

这里我尝试了一下,在第一章中的拉取源码就卡住很久了,我花费了半天,也没能从 GitHub 上把 react 源码拉下来,后来我突然想到码云有很多镜像,尝试之后发现速度真的快,所以推荐码云镜像作为国内下载地址,这个镜像在地址是:

https://gitee.com/mirrors/react

我的环境:

  • 南方联通
  • 代理和cnpm均尝试

作为小白最怕这样一开始卡住,这里感谢一下码云😝

关于 Fiber 架构的心智模型 的疑惑

1635835128(1)

卡子哥,这节代数效应与Fiber中的描述是否有误?

所谓代数效应就是解耦程序逻辑和具体实现,目的是:

JS 中并没有代数效应的概念,Generator 污染外层函数也没有践行代数效应的理念,正因此 React 自己实现 Fiber,作为协程的一种实现,并且践行了代数效应,算是对 JS 的一种扩展。

结论:“所以,我们可以将纤程(Fiber)、协程(Generator)理解为代数效应**在JS中的体现” 应该修改为 “所以,我们可以将纤程(Fiber)理解为代数效应**在JS中的体现”。

不知描述是否有误,请多指教!

理念篇 - React15 架构 的疑问

1635651069(1)
卡子哥,我知道你想表达的是旧架构栈调和 无法实现“可中断异步更新”,但是关于" Reconciler和Renderer是交替工作的,当第一个li在页面上已经变化后,第二个li再进入Reconciler " 这一句话的表述是否存在问题呢?

1635651405(1)

以上来自 陈屹的《深入 React 技术栈》,针对的是 React15。

1635651812(1)
以上是官方文档对旧架构栈调和的实现说明:https://zh-hans.reactjs.org/docs/implementation-notes.html。

综上所述,我的理解是:Reconciler和Renderer是交替工作的,但是在一次更新中 协调器Reconciler 工作结束后才是渲染器 Render 工作,当渲染器处理 第一个li在页面上的变化,紧接着就会处理第二个li在页面上的变化,如果这时候中途中断更新会看见不完整的变化,但实际上旧架构 Reconciler 和 Render 一起工作,并且各自是不可中断的,是一个长任务,导致帧的 Layout / Paint 缺失,也就是掉帧,给用户的体验就是卡顿,新架构启用 fiber,使得Reconciler工作异步可中断,长任务分割为短任务,保证页面渲染不掉帧,Render 同步工作,保证页面变化完整性

不知道有什么错误的地方,希望卡子哥指点下~

hook的数据结构有问题

你的文章里hook是单链表,文章《react hooks not magic,just arrays》里说是数组,怎么会有这种冲突的说法呢

看到 React15架构 这一节的两个疑问

@BetaSu 看到React15架构这一节,有两个疑问

  1. Reconciler 与 Renderer 是交错进行的,例子里描述的中断更新这一步,是不能实际实现的吧?
    image

  2. 文章里提到 Reconciler 与 Renderer 交替进行,而 Reconciler 的步骤包括调用 render 方法,那意思是 render 方法会被调用很多次吗?次数取决于元素或者组件的个数?
    应该不是这样,是我哪里理解的有问题吗

关于极简react的useStateDemo的问题

if (hook.queue.pending) {
  let firstUpdate = hook.queue.pending.next;
  do {
    const action = firstUpdate.action;
    baseState = action(baseState);
    firstUpdate = firstUpdate.next;
  } while (firstUpdate !== hook.queue.pending)
  hook.queue.pending = null;
}

hook.queue.pending = null;为空的话dispatchAction方法的else逻辑不会执行?

update数据结构

极简hooks实现一章中,存在多个update时,update数据结构的queue(环状单向链表)是只保留第一个和最后一个update吗?这样设计是为啥呢?

学习中的一些小建议。

感谢

非常感谢repo主的文章,看过很多react分析的文章,能通过这样言简意赅的方式讲出来的真的不多,在此感谢,受教了!

一些建议 (可能只是自己没理解透彻,轻拍)

https://react.iamkasong.com/process/fiber.html
https://react.iamkasong.com/process/reconciler.html

beginWork&completeWork 以下简称B&C

render阶段 中对于B&C流程(callstack分析和讲解)非常好,但是感觉缺少了我们在initial Mount和update进入B&C,到底是怎么建立起来的Fiber树 (child, silbing, return, DFS相关的workLoop) 的呢 。如果能在这方面有所讲解感觉会更容易我们理解B&C的意义。

个人感觉这方面比较好的文章:

  1. https://indepth.dev/the-how-and-why-on-reacts-usage-of-linked-list-in-fiber-to-walk-the-components-tree/
  2. https://indepth.dev/inside-fiber-in-depth-overview-of-the-new-reconciliation-algorithm-in-react/

自己会继续追您写的解析哈,感谢!

多节点diff时候,如果key从abcd变成1234的情况没有分析

如题,
按照多节点二次遍历的讲解思路,这里好像只介绍了第两次遍历后,old/new都没遍历完的情况中默认节点一一对应只是位置变化,但对于新节点的key完全变成新的(此种情况也会触发立即跳出第一次遍历,且在文档中介绍的第二次遍历中符合第四种情况【newChildren与oldFiber都没遍历完】),但此时,在oldMap中一个newFiber也找不存在,此种更新节点场景没有介绍

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.