1、前言
前几节我们实现了React基本功能,本节我们来添加React16.8的核心功能hooks。
编写一个计数器的功能;
// src/index
import React from '../react'
function Counter() {
const [state, setState] = React.useState(1)
return (
<div>
<h1 >
Count: {state}
</h1>
<button onClick={() => setState(c => c + 1)}>+1</button>
</div>
)
}
const element = <Counter />
React.render(element, document.getElementById("root"))
2、实现步骤
2.1 添加useState函数
// react/react-dom.js
function useState(initial){
// todo
}
2.2 初始化全局变量
我们知道函数每重新调用一次,内部状态就会丢失,所以我们需要一个记录内部内部状态的变量;
设置正在工作的fiber和添加一个数组来记录多次调用useState,使用索引来追踪;
let wipFiber = null
let hookIndex = null
/**
* 函数组件处理
* @param {*} fiber
*/
function updateFunctionComponent(fiber) {
wipFiber = fiber
hookIndex = 0
wipFiber.hooks = []
// 省略
}
2.3 添加useState函数的state
/**
* @param {*} initial 传进来的初始值
* @returns
*/
function useState(initial) {
// 检查是否有旧的hooks
const oldHook =
wipFiber.alternate &&
wipFiber.alternate.hooks &&
wipFiber.alternate.hooks[hookIndex]
// 如果有旧的,就复制到新的,如果没有初始化
const hook = {
state: oldHook ? oldHook.state : initial,
}
wipFiber.hooks.push(hook)
hookIndex++
return [hook.state]
}
2.4 添加useState函数的setState
设置一个新的正在进行的工作根作为下一个工作单元,这样工作循环就可以开始一个新的渲染阶段;
// 设置hooks状态
const setState = action => {
debugger
hook.queue.push(action)
// 设置一个新的正在进行的工作根作为下一个工作单元,这样工作循环就可以开始一个新的渲染阶段
wipRoot = {
dom: currentRoot.dom,
props: currentRoot.props,
alternate: currentRoot,
}
nextUnitOfWork = wipRoot
deletions = []
}
2.5 更新状态
function useState(initial) {
// 省略
const actions = oldHook ? oldHook.queue : []
actions.forEach(action => {
hook.state = typeof action === 'function' ? action(hook.state) : action
})
// 省略
}
3、运行结果
把useState函数结果导出;
运行结果: