个人博客 个人博客
首页
  • 前端
  • 后端
  • Git
  • Docker
  • 网络
  • 操作系统
工具
阅读
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

董先亮

前端react开发
首页
  • 前端
  • 后端
  • Git
  • Docker
  • 网络
  • 操作系统
工具
阅读
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Vue

  • React

    • 三方库
    • useEffect与useLayoutEffect
    • useState与useEffect原理
      • memo
      • useCallback
      • useMemo
      • useRef
    • 前端框架
    • React
    NeverStop1024
    2023-02-15
    目录

    useState与useEffect原理

    # useState与useEffect实现原理

    import React from "react";
    import * as ReactDOMClient from "react-dom/client";
    const AppDOM = React.createRef()
    let root
    
    let stateArrs = []
    let stateIndex = 0
    let effectIndex = 0
    
    const useState = (initValue) => {
      stateArrs[stateIndex] = stateArrs[stateIndex] ?? initValue
      const setState = (index) => {
        stateIndex ++
        return (newState) => {
          stateArrs[index] = newState
          if(!root){
            root = ReactDOMClient.createRoot(AppDOM.current);
          }
          stateIndex = 0
          effectIndex = 0
          root.render(<Children />);
        }
      }
      return [stateArrs[stateIndex], setState(stateIndex)]
    }
    
    let preArrs = []
    const useEffect = (callback, relyArrs) => {
      if(!preArrs[effectIndex] || !relyArrs.every((item, index) => item === preArrs[effectIndex][index])){
        callback()
      }
      preArrs[effectIndex] = relyArrs
      effectIndex++
    }
    
    const Children = () => {
      const [count, setCount] = useState(1)
      const [count2, setCount2] = useState(3)
    
      useEffect(() => {
        console.log('count发生变化')
      },[count])
    
      useEffect(() => {
        console.log('count2发生变化')
      },[count2])
    
      useEffect(() => {
        console.log('count3发生变化')
      },[])
    
      return (
          <>
            <div>useState与useEffect原理</div>
            <div>count1值为:{count}</div>
            <button onClick={() => setCount(count + 1)}>改变count1</button>
            <div>count2值为:{count2}</div>
            <button onClick={() => setCount2(count2 + 1)}>改变count2</button>
          </>
      )
    }
    
    const App = () => {
      return (
          <div ref={AppDOM}>
            <Children/>
          </div>
      )
    }
    
    export default App
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71

    # 1. useState原理

      1.useState是依赖于外部一个变量stateArrs用来存储每次的状态,由于可以多次调用,所以这个变量是个数组类型。每次执行useState取出对应索引stateIndex的值,进行返回。
      2.setState是利用了闭包的思想,将每次执行useState时的索引stateIndex存下来,作为setState的私有变量。这样每次调用setState就会针对具体的索引值stateArrs[stateIndex]去修改了。
      3.调用setState时,state改变后,会重新render,把stateIndex恢复初始值0

    # 2. useEffect原理

      1.useEffect也是依赖于外部变量preArrs,每次调用useEfffect()都会与上次保存的依赖值做对比,如果不相同就执行callback回调。
      2.由于useEffect可以被多次调用,所以preArrs也是一个数组,也需要一个变量effectIndex来记录每次调用的索引。

    # 常见问题

    1. useState是同步还是异步?
       useState 本身是同步的,调用 useState 函数返回一个更新后的状态和更新状态的函数,这个更新状态的函数可以被同步调用。在调用状态更新函数时,React 会立即将新状态更新到组件中并重新渲染组件。但是,因为 React 对状态的批量更新机制,可能会导致在一个 setState 中多个状态更新合并成一次渲染,这种情况下,setState 是异步的。当多个 setState 进行批量更新时,React 会在当前执行栈完成后才更新组件。但是,这种情况是由 React 决定的,对于我们的代码来说,setState 仍然是同步的。

    编辑 (opens new window)
    上次更新: 2023/02/16
    useEffect与useLayoutEffect
    memo

    ← useEffect与useLayoutEffect memo→

    最近更新
    01
    mock使用
    07-12
    02
    websocket即时通讯
    07-12
    03
    前端面试题
    07-09
    更多文章>
    Theme by Vdoing | Copyright © 2022-2023 NeverStop1024 | MIT License
    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式