1、前言

前几节我们实现了React基本功能,本节我们来添加React16.8的核心功能hooks。

编写一个计数器的功能;

  1. // src/index
  2. import React from '../react'
  3. function Counter() {
  4. const [state, setState] = React.useState(1)
  5. return (
  6. <div>
  7. <h1 >
  8. Count: {state}
  9. </h1>
  10. <button onClick={() => setState(c => c + 1)}>+1</button>
  11. </div>
  12. )
  13. }
  14. const element = <Counter />
  15. React.render(element, document.getElementById("root"))

2、实现步骤

2.1 添加useState函数

  1. // react/react-dom.js
  2. function useState(initial){
  3. // todo
  4. }

2.2 初始化全局变量

我们知道函数每重新调用一次,内部状态就会丢失,所以我们需要一个记录内部内部状态的变量;

设置正在工作的fiber和添加一个数组来记录多次调用useState,使用索引来追踪;

  1. let wipFiber = null
  2. let hookIndex = null
  3. /**
  4. * 函数组件处理
  5. * @param {*} fiber
  6. */
  7. function updateFunctionComponent(fiber) {
  8. wipFiber = fiber
  9. hookIndex = 0
  10. wipFiber.hooks = []
  11. // 省略
  12. }

2.3 添加useState函数的state

  1. /**
  2. * @param {*} initial 传进来的初始值
  3. * @returns
  4. */
  5. function useState(initial) {
  6. // 检查是否有旧的hooks
  7. const oldHook =
  8. wipFiber.alternate &&
  9. wipFiber.alternate.hooks &&
  10. wipFiber.alternate.hooks[hookIndex]
  11. // 如果有旧的,就复制到新的,如果没有初始化
  12. const hook = {
  13. state: oldHook ? oldHook.state : initial,
  14. }
  15. wipFiber.hooks.push(hook)
  16. hookIndex++
  17. return [hook.state]
  18. }

2.4 添加useState函数的setState

设置一个新的正在进行的工作根作为下一个工作单元,这样工作循环就可以开始一个新的渲染阶段;

  1. // 设置hooks状态
  2. const setState = action => {
  3. debugger
  4. hook.queue.push(action)
  5. // 设置一个新的正在进行的工作根作为下一个工作单元,这样工作循环就可以开始一个新的渲染阶段
  6. wipRoot = {
  7. dom: currentRoot.dom,
  8. props: currentRoot.props,
  9. alternate: currentRoot,
  10. }
  11. nextUnitOfWork = wipRoot
  12. deletions = []
  13. }

2.5 更新状态

  1. function useState(initial) {
  2. // 省略
  3. const actions = oldHook ? oldHook.queue : []
  4. actions.forEach(action => {
  5. hook.state = typeof action === 'function' ? action(hook.state) : action
  6. })
  7. // 省略
  8. }

3、运行结果

把useState函数结果导出;
image.png

image.png

运行结果:
image.png

4、本节代码

代码地址:https://github.com/linhexs/mini-react/tree/8.hooks