我不是 React 机制本身的专家,但使用一些 CS 概念的非常简化的版本背后的想法可能如下:
首先,React 必须有一个应用程序中所有组件的列表,我们将用一个列表来简化它,但它实际上是一棵树:
const nodes = <>
<h1>My Counter</h1>
<Counter />
<div>
</>
所以此时,如果您的应用程序是扁平的,DummyReactDOM.render(nodes) 将创建这些节点的列表“:
nodes = [ h1, Counter, div ]
当useState 被调用时会变得很棘手,React 会保存某种状态(记忆状态),例如 Counter 节点可能看起来像这样:
function Counter() {
[ counter, setCounter ] = useState(0);
}
这将为节点添加一个状态:
node Counter = {
state : {
counter: 0
next : null
}
}
现在,当我们单击组件并调用 setCounter(counter + 1) 时会发生什么? 下一个状态被添加到队列中:
node Counter = {
state : {
counter : 0,
next : {
state : {
counter : 1, // <-- setCounter(counter + 1 happens)
next : null,
}
}
}
}
// firstState.next -> secondState.next -> null
现在,调度程序 是了解哪些组件需要重新渲染的主脑。这是一种非常不切实际但易于理解的方式:
while (true) {
// sleepForABit();
if (currentNode.state.next !== null && currentNode.state !== currentNode.state.next) {
currentNode.state = currentNode.state.next;
currentNode.component.render(); // or functionalComponent() call
}
currentNode = currentNode.next
}
如果它是一个节点列表,这是一个简单的情况,但显然由于一个节点需要重新渲染,React 会检查它的子节点。重要的是要注意重新渲染并不是那么昂贵,昂贵的部分是重新创建 DOM 节点(并且在较小程度上更新它们),因此检查子节点的性能非常好。
希望这会有所帮助!
如果你想知道为什么我们可以在没有 counter = 0 的情况下执行 setCounter(counter + 1),React 保证在某些事件上重新渲染节点(onClick 是其中之一)。