6-1. 实现 useState

本次课程我们来实现我们mini react项目中的useState.

期望实现的效果

  • app.js
tsx 复制代码
import React from "./core/React.js";
​
function Foo() {
  const [count, setCount] = React.useState(10)
  function handleClick() {
    setCount((prevCount) => prevCount + 1)
  }
​
  return (
    <div>
      <h1>foo</h1>
      {count}
      <button onClick={handleClick}>click</button>
    </div>
  );
}
function Bar() {
  const [count, setCount] = React.useState(10)
  function handleClick() {
    setCount((prevCount) => prevCount + 1)
  }
​
  return (
    <div>
      <h1>bar</h1>
      {count}
      <button onClick={handleClick}>click</button>
    </div>
  );
}
​
function App() {
  return (
    <div>
      <Foo></Foo>
    </div>
  );
}
​
export default App;

能正常展示出数据

tsx 复制代码
function useState(initial) {
    const stateHook = {
        state: initial
    }
    
    function setState(action) {
        stateHook.state = action
    }
    return [stateHook.state, setState]
}
​
​
const React = {
    render,
    useState,
    createElement,
    update
}

实现数据的修改

tsx 复制代码
function useState(initial) {
    let currentFiber = wipFiber;
    const oldHook = currentFiber.alternate?.stateHook
​
    const stateHook = {
        state: oldHook?.state || initial
    }
    
    currentFiber.stateHook = stateHook
​
    function setState(action) {
        stateHook.state = action(stateHook.state)
        wipRoot = {
            ...currentFiber,
            alternate: currentFiber
        }
        nextWorkOfUnit = wipRoot
    }
    return [stateHook.state, setState]
}
​

实现多个hooks的情况

  • app.js
tsx 复制代码
import React from "./core/React.js";
​
function Foo() {
  const [count, setCount] = React.useState(10)
  const [bar, setBar] = React.useState('bar')
  function handleClick() {
    setCount((prevCount) => prevCount + 1)
    setBar((prevBar) => prevBar + 'bar')
  }
​
  return (
    <div>
      {count}
      {bar}
      <button onClick={handleClick}>click</button>
    </div>
  );
}
function Bar() {
  const [count, setCount] = React.useState(10)
  function handleClick() {
    setCount((prevCount) => prevCount + 1)
  }
​
  return (
    <div>
      <h1>bar</h1>
      {count}
      <button onClick={handleClick}>click</button>
    </div>
  );
}
​
function App() {
  return (
    <div>
      <Foo></Foo>
    </div>
  );
}
​
export default App;

现在出现问题,这是因为现在就用了一个Hook

改成数组

tsx 复制代码
function updateFunctionComponent(fiber) {
    stateHooks = []
    stateHookIndex = 0
    wipFiber = fiber
    const children = [fiber.type(fiber.props)]
    reconcileChildren(fiber, children)
}
​
let stateHooks
let stateHookIndex
function useState(initial) {
    let currentFiber = wipFiber;
    const oldHook = currentFiber.alternate?.stateHooks[stateHookIndex]
​
    const stateHook = {
        state: oldHook ? oldHook.state : initial
    }
​
    stateHookIndex++
    stateHooks.push(stateHook)
​
    currentFiber.stateHooks = stateHooks
​
    function setState(action) { 
        stateHook.state = action(stateHook.state)
        wipRoot = {
            ...currentFiber,
            alternate: currentFiber
        }
        nextWorkOfUnit = wipRoot
    }
    return [stateHook.state, setState]
}

现在正常了

相关推荐
子兮曰8 分钟前
后端字段又改了?我撸了一个 BFF 数据适配器,从此再也不怕接口“屎山”!
前端·javascript·架构
万少2 小时前
使用Trae轻松安装openclaw的教程-附带免费token
前端·openai·ai编程
浪浪山_大橙子2 小时前
OpenClaw 十分钟快速,安装与接入完全指南 - 推荐使用trae 官方 skills 安装
前端·人工智能
忆江南2 小时前
iOS 可视化埋点与无痕埋点详解
前端
离开地球表面_992 小时前
金三银四程序员跳槽指南:从简历到面试再到 Offer 的全流程准备
前端·后端·面试
_柳青杨2 小时前
跨域获取 iframe 选中文本?自己写个代理中间层,再也不求后端!
前端
比尔盖茨的大脑2 小时前
事件循环底层原理:从 V8 引擎到浏览器实现
前端·javascript·面试
天才熊猫君2 小时前
Vue3 命令式弹窗原理和 provide/inject 隔离机制详解
前端
bluceli2 小时前
Vue 3 Composition API深度解析:构建可复用逻辑的终极方案
前端·vue.js
程序员ys2 小时前
前端权限控制设计
前端·vue.js·react.js