崔大mini-react结课收获之快照

代码写完就忘了。下面挑一个最印象深刻的点来简单说说。快照思想

useState中的快照

处理各个fiber任务的时候,碰到了函数类型的fiber,会通过一个全局变量wipFiber(work in progress fiber)给保存起来。useState返回的更新函数updater要如何拿到当前的函数fiber呢?如果直接引用wipFiber,那调用updater的时候,引用永远都是最后的那个函数fiber了。所以要在内部保存一个局部变量。

这个变量的意义就是在处理到当前函数组件的那个时刻,把过去的fiber保存下来。render是一个巨大的流程,而这个变量可以把某个阶段的状态保存住。就像是一个电影,而在某一帧处拍了一张照片。这是我第一次从mini-react中感受到快照这个概念。

function useState(initialValue) {
  const currentFiber = wipFiber
  // ...

  function setHandler(action) {
  // ...

    wipRoot = {
      ...currentFiber, // 重点在这里
      alternate: currentFiber
    }
    nextUnitOfWork = wipRoot
  }


  return [stateHook.state, setHandler]
}

React.createElement也是一个快照

function App() {
  const [count, setCount] = React.useState(10)
  const [name, setName] = React.useState('wyq')

  function handleClick() {
    setCount(c => c + 1)
    setName(n => n + ' -love')
  }

  React.useEffect(() => {
    console.log('count useEffect')
    return () => {
      console.log('count cleanup')
    }
  }, [count])

  return (
    <div>
      <h1>App</h1>
      <h2>{count}</h2>
      <h2>{name}</h2>
      <button onClick={handleClick}>+1</button>
    </div>
  )
}

在刚写到从根节点root更新节点的时候,对使用currentRoot.alternate.props.children还有疑问。我想两次都使用相同的[el],最后生成的真实dom不也是一样的吗?怎么可能更新呢?

但是实际处理时,函数组件就是和普通的函数一样,而且是纯函数。规定了props输入,它return 输出的内容一定是只有唯一一种可能。函数组件里再使用别的函数组件也同理。当你修改了某些状态,触发的rerender,就相当于触发了一大堆React.createElement()的调用,调用时入参改变了,那createElement返回值自然就改变了。

每一次render后生成的dom也像是一张快照,就是静态的,只有触发了rerender,才会拍下一张照片。

这种快照思想在工作中基本用不到。因为只适合在有整个大流程中保存某时刻的片段才适合用。平时用仅仅是函数中去引用外部函数。流程的循环调用可能只有设计框架才适合吧。