个人博客 个人博客
首页
  • 前端
  • 后端
  • 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-16
    目录

    useRef

    # useRef原理

    import React from "react";
    import * as ReactDOMClient from "react-dom/client";
    const AppDOM = React.createRef()
    let root
    let refIndex = 0
    
    const render = () => {
      if(!root){
        root = ReactDOMClient.createRoot(AppDOM.current);
      }
      refIndex = 0
      root.render(<Children />);
    }
    
    const refs = []
    const useRef = (initVal) => {
       if(!refs[refIndex]){
         refs[refIndex] = {current: initVal}
       }
       refIndex++
       return refs[refIndex - 1]
    }
    
    const Children = () => {
      const count1 = useRef(0)
      const count2 = useRef(0)
      const showCounts = () => {
        setTimeout(() => {
          alert(`count1:${count1.current}  count2:${count2.current}`)
        },5000)
      }
      return (
          <div>
            <div>
              count1值为:{count1.current}
              <button onClick={() => count1.current = ++count1.current}>
                改变count1
              </button>
            </div>
            <div>
              count2值为:{count2.current}
              <button onClick={() => count2.current = count2.current + 1}>
                改变count2
              </button>
            </div>
            <button onClick={() => render()}>
              重新render
            </button>
            <button onClick={showCounts}>
              5秒后输出count1、count2
            </button>
          </div>
      )
    }
    
    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

    # 与useState区别

    • useRef()是返回一个对象{current: state},所以不管什么时候取useRef赋值的变量,都是最新的值。因为每次返回都是同一个对象的引用,每次修改count = count.current + 1都是改的这个对象的属性。
    • 而useState每次调用返回的都是一个新的引用,所以就会造成下面这个问题:
    import {useState} from "react";
    
    const App = () => {
      const [count, setCount] = useState(0)
    
      const handleShowClick = () => {
        setTimeout(() => {
          alert(`count值为${count}`)
        },5000)
      }
      return (
          <div>
            <button onClick={() => setCount(count + 1)}>count加1</button>
            <button onClick={handleShowClick}>展示count</button>
          </div>
      )
    }
    
    export default App
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

      点击【展示count】按钮后,5秒内多次点击【count加1】,最终展示效果为"count值为0"。
      这是因为每次render都会有一个作用域,点击【展示count】后,调用handleShowClick,此时这个方法体内拿到的count是0,可以理解为函数组件每次渲染都会形成一个闭包,闭包内有自己的作用域。所以5秒内不管改变多少次count值,最终展示效果都是"count为0"。

    # 如何解决useState引起的闭包问题。

    用useRef替换useState

    import {useRef} from "react";
    
    const App = () => {
      const count = useRef(0)
    
      const handleShowClick = () => {
        setTimeout(() => {
          alert(`count值为${count.current}`)
        },5000)
      }
      return (
          <div>
            <button onClick={() => count.current = count.current + 1}>count加1</button>
            <button onClick={handleShowClick}>展示count</button>
          </div>
      )
    }
    
    export default App
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19

    # 使用场景

    1. 存dom
    2. 存值(任何时候都可以拿到最新值)
    编辑 (opens new window)
    上次更新: 2023/02/16
    useMemo

    ← useMemo

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