使用 useReducer
在此之前,需要在demo/which-react.js
中将useReducer
从react中引入,并将ReactDOM
更换为从react-dom
引入
import { Component, Fragment, useReducer } from 'react';
import ReactDOM from 'react-dom/client';
// import { Component, Fragment } from '../src/react';
// import ReactDOM from '../src/react-dom';
export {Component,Fragment,useReducer,ReactDOM
}
在demo/src/main.jsx
中的 FunctionComponent 中添加useReducer
function FunctionComponent(props) {const [state, dispatch] = useReducer(x => x + 1, 0)return (<div className='function'><p>{props.name}</p><div>{state}</div><button onClick={dispatch} >+1</button></div>)
}
那么每次点击button
都会将state
+ 1,有了我们想要的效果,接下来我们去实现它
实现 useReducer
将 React 的引入重新设定为自己写的(修改which-react.js),创建src/ReactFiberHooks.ts
export function useReducer(reducer, initalState) {const dispatch = () => {console.log('useReducer dispatch log')}// 暂时直接返回return [initalState, dispatch]
}
接着会发现点击 button 没有触发 dispatch 里的 console,这是因为我们还没有实现 React 事件,暂时只是将事件作为属性挂在dom上
// src/utils.ts
export function updateNode(node, nextVal) {Object.keys(nextVal).forEach(key => {if (key === 'children') {if (isStringOrNumber(nextVal[key])) {node.textContent = nextVal[key]}} else {node[key] = nextVal[key] // 这里直接当作属性放到 dom 上了}})
}
这里我们先简单处理一下,能让事件能响应(注意这里并不是真正的 React 事件实现方式)
export function updateNode(node: HTMLElement, nextVal) {Object.keys(nextVal).forEach(key => {if (key === 'children') {if (isStringOrNumber(nextVal[key])) {node.textContent = nextVal[key]}} else if (key.slice(0, 2) === 'on') {// 简单处理一下事件响应(并不是真正的React 事件)const eventName = key.slice(2).toLocaleLowerCase()node.addEventListener(eventName, nextVal[key])} else {node[key] = nextVal[key]}})
}
点击按钮能让console.log('useReducer dispatch log')
执行出来了
实现 mount 时的 useReducer
import { Fiber } from "./ReactFiber"
interface Hook {memoizedState: any, // statenext: null | Hook // 下