Skip to content

Commit b796bca

Browse files
committed
七: 实现 hooks
1 parent a0e9d46 commit b796bca

File tree

3 files changed

+62
-5
lines changed

3 files changed

+62
-5
lines changed

src/index.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component } from './mini-react/react';
1+
import { Component, useState } from './mini-react/react';
22
import ReactDOM from './mini-react/react-dom';
33
import './index.css';
44

@@ -27,10 +27,16 @@ class ClassComponent extends Component {
2727
}
2828

2929
function FunctionComponent(props) {
30+
const [count, setCount] = useState(0);
31+
const addCount = () => {
32+
setCount(count + 1);
33+
};
3034
return (
3135
<div className="function-component">
3236
<div>this is a function Component</div>
3337
<div>prop value is: {props.value}</div>
38+
<div>count is: {count}</div>
39+
<input type="button" value="add count" onClick={addCount} />
3440
</div>
3541
);
3642
}

src/mini-react/fiber.js

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ let nextUnitOfWork = null;
66
let workInProgressRoot = null; // 当前工作的 fiber 树
77
let currentRoot = null; // 上一次渲染的 fiber 树
88
let deletions = []; // 要执行删除 dom 的 fiber
9+
let currentFunctionFiber = null; // 当前正在执行的函数组件对应 fiber
10+
let hookIndex = 0; // 当前正在执行的函数组件 hook 的下标
911

1012
// 将某个 fiber 加入 deletions 数组
1113
export function deleteFiber(fiber) {
@@ -27,6 +29,16 @@ export function commitRender() {
2729
nextUnitOfWork = workInProgressRoot;
2830
}
2931

32+
// 获取当前的执行的函数组件对应的 fiber
33+
export function getCurrentFunctionFiber() {
34+
return currentFunctionFiber;
35+
}
36+
37+
// 获取当前 hook 下标
38+
export function getHookIndex() {
39+
return hookIndex++;
40+
}
41+
3042
// 创建 rootFiber 作为首个 nextUnitOfWork
3143
export function createRoot(element, container) {
3244
workInProgressRoot = {
@@ -57,9 +69,7 @@ function performUnitOfWork(workInProgress) {
5769
updateClassComponent(workInProgress);
5870
} else {
5971
// 函数组件
60-
const { props, type: Fn } = workInProgress.element;
61-
const jsx = Fn(props);
62-
children = [jsx];
72+
updateFunctionComponent(workInProgress);
6373
}
6474
}
6575

@@ -114,6 +124,16 @@ function updateClassComponent(fiber) {
114124
reconcileChildren(fiber, [jsx]);
115125
}
116126

127+
// 函数组件的更新
128+
function updateFunctionComponent(fiber) {
129+
currentFunctionFiber = fiber;
130+
currentFunctionFiber.hooks = [];
131+
hookIndex = 0;
132+
const { props, type: Fn } = fiber.element;
133+
const jsx = Fn(props);
134+
reconcileChildren(fiber, [jsx]);
135+
}
136+
117137
// 处理循环和中断逻辑
118138
function workLoop(deadline) {
119139
let shouldYield = false;

src/mini-react/react.js

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { commitRender } from './fiber';
1+
import { commitRender, getCurrentFunctionFiber, getHookIndex } from './fiber';
22
export class Component {
33
constructor(props) {
44
this.props = props;
@@ -26,3 +26,34 @@ Component.prototype.setState = function (param) {
2626
Component.prototype._UpdateProps = function (props) {
2727
this.props = props;
2828
};
29+
30+
export function useState(initial) {
31+
const currentFunctionFiber = getCurrentFunctionFiber();
32+
const hookIndex = getHookIndex();
33+
// 取当前执行的函数组件之前的 hook
34+
const oldHook = currentFunctionFiber?.alternate?.hooks?.[hookIndex];
35+
36+
// oldHook存在,取之前的值,否则取现在的值
37+
const hook = {
38+
state: oldHook ? oldHook.state : initial,
39+
queue: [], // 一次函数执行过程中可能调用多次 setState,将其放进队列一并执行
40+
};
41+
42+
const actions = oldHook ? oldHook.queue : [];
43+
actions.forEach((action) => {
44+
hook.state = action(hook.state);
45+
});
46+
47+
const setState = (action) => {
48+
if (typeof action === 'function') {
49+
hook.queue.push(action);
50+
} else {
51+
hook.queue.push(() => {
52+
return action;
53+
});
54+
}
55+
commitRender();
56+
};
57+
currentFunctionFiber.hooks.push(hook);
58+
return [hook.state, setState];
59+
}

0 commit comments

Comments
 (0)