Skip to content

Fix hook effect schedule - #870

Merged
yuanyan merged 18 commits into
alibaba:masterfrom
yongningfu:fix-hook-effect-schedule
Jan 17, 2019
Merged

Fix hook effect schedule#870
yuanyan merged 18 commits into
alibaba:masterfrom
yongningfu:fix-hook-effect-schedule

Conversation

@yongningfu

Copy link
Copy Markdown
Collaborator

主要解决三个问题:

  1. rax渲染时候,如果调度更新,应该咋办的问题
  2. hook effect 的执行时机问题
  3. schedule.js写法的bug
const setImmediate = typeof setImmediate === 'undefined' ? setImmediatePolyfill : setImmediate;

这个应该是js写法中 比较常见的bug, 先声明 const setImmediate, 然后使用 typeof setImmediate, 这个setImmediate应该是我们声明的那个setImmediate,所以typeof setImmediate === 'undefined' 一定为true

渲染中 发生更新如何解决?

setState应该可以在任何的生命周期方法中调用

  1. 渲染中更新, 主要发生在组件的生命周期中使用 setState,这些状态应该延迟设置,设置组件为dirty, 等待下一次更新
  2. raxDOM.render() 这个方法也可以渲染一个组件,为了方便的调度,把render方法也设置成一个更新的模型,这样的话,我们就可以走统一的更新调度模型了

实现中有几个需要注意的点:

  1. root.js 中 初始状态为 [] 而不是 null, 因为null为生成一个注释节点,render()初始化的时候,这个注释节点不是我们想要的,root真正setState的时候,也无需走diff
  2. render初始化的组件的时候,生成rootinstance, 先this.set(container, rootInstance); 然后在
    rootInstance.setState({element,});
    因为setState可能会延迟渲染,先注册到container中,如果后面还有同一个container的render ,可以实现
    render的batch update,有/tests/render.js中有对应的case
  3. createPortal 上下文传递的方法: 由于render使用了 setState更新某些,setState模型应该是上下文不改变的,但是createPortal可能存在上下文的改变,所以额外使用了_penddingContext 这个字段(尝试过getChildContext, 但是这个方法会生成新的对象,很难将父组件的context透传)

hook effect的调度

effect应该是下一次渲染前 会执行, 如何去理解下一次渲染前??

比如 A.setState --> A 更新中发生了 B, C需要调度更新,B, C再更新的时候,又调度了 D E F更新

这里实现的effect刷新的模型是 A -> flush effect -> B C -> flush effect -> D E F -> flush effect

实现

官方的effect的case 基本已经覆盖了
可以在生命周期中执行setState
rax在hook的使用下,更新也是同步的

本来想分几个pr的,但是hook存在,调度和hook耦合,不好分开pr

@CLAassistant

CLAassistant commented Jan 14, 2019

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you all sign our Contributor License Agreement before we can accept your contribution.
0 out of 2 committers have signed the CLA.

❌ yongningfu
❌ yuanyan
You have signed the CLA already but the status is still pending? Let us recheck it.

@yuanyan

yuanyan commented Jan 15, 2019

Copy link
Copy Markdown
Collaborator

OK,我看下

Comment thread packages/rax/src/vdom/instance.js Outdated
// using _penddingContext to pass new context
prevRootInstance._internal._penddingContext = parentContext;
}
prevRootInstance.setState({

@yuanyan yuanyan Jan 15, 2019

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

通过 setState 来触发更新是一个不错的方式,但 rootInstance 暴露的接口是可以更语义化些,比如 prevRootInstance.update(element)

Comment thread packages/rax/src/vdom/instance.js Outdated
let defaultContext = parentContext || {};
let rootInstance = renderedComponent.mountComponent(container, null, defaultContext);
this.set(container, rootInstance);
rootInstance.setState({

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

这里这样改的话,test case应该过不了吧? A 正在更新, render(B, container) 即发生了B的mount, B应该延迟mount,基于此,当时这里render设计的模型是 render的组件无论mount还是update 都统一走更新的逻辑,这样的话,都能被更新模型调度到,更新模型会检测到当前有A组正在更新, 以此来延迟B mount

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got

@yuanyan
yuanyan merged commit 6f85f55 into alibaba:master Jan 17, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants