react Hooks 之 useRef

1.useRef是什么

官网:

const refContainer = useRef(initialValue);
1.useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。
2.返回的 ref 对象在组件的整个生命周期内保持不变
3.本质上,useRef 就像是可以在其 .current 属性中保存一个可变值的“盒子”。

1.1 useRef 和 createRef的区别

ref 是一种访问 DOM 的主要方式。如果你将 ref 对象以

形式传入组件,则无论该节点如何改变,React 都会将 ref 对象的 .current 属性设置为相应的 DOM 节点。

然而,useRef() 比 ref 属性更有用。它可以很方便地保存任何可变值,其类似于在 class 中使用实例字段的方式。

这是因为它创建的是一个普通 Javascript 对象。而 useRef() 和自建一个 {current: …}对象的唯一区别是,useRef 会在每次渲染时返回同一个 ref 对象

useRef createRef
作用 访问dom 访问dom
保存值 保存任何可变值 访问dom
返回值 每次渲染时返回同一个 ref 对象 返回新的普通js对象

当 ref 对象内容发生变化时,useRef 并不会通知你。变更 .current 属性不会引发组件重新渲染。如果想要在 React绑定或解绑 DOM 节点的 ref 时运行某些代码,则需要使用回调 ref 来实现。

2.为什么要用useRef

因为在 hooks 中,我们所声明的所有变量是只属于它的闭包,所以,我们无法做到变量的一个共享。

然后不可变的 state 并不适合我们存储一些不参与 UI 显示的变量(state不适合用来存储一些不参与UI的变量,普通变量会在每次render时重置)。

好在hooks 为我们提供了 useRef 去存储可变且不参与 UI 显示的变量,并且可以在每一轮 render 中共享。

useRef 不仅可以用来存储对 Dom 元素的引用(它的本意),更可以用来存储我们需要在每轮 render 中共享且可变的变量。

所以通过useRef我们可以解决很多需要变量共享的问题。

3.useRef如何使用

一个常见的用例便是命令式地访问子组件:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

4.什么情况下可以使用useRef

4.1 获取最新的state

官方默认的setState方法移除了回调函数,但我们有时候的业务场景需要我们同步拿到变量的最新变化值,以便做下一步操作,这时我们可以通过useRef来拿到最新状态值。

import React, { useState, memo, useRef, useEffect, createRef } from 'react'
export default memo(function GetLatestDemo() {
    const [value, setValue] = useState(0)
    const currentRef = useRef(null)
    const handleAdd = () => {
        setValue(value => value + 1)
        setTimeout(() => { console.log(`value`, value) }, 0);//获取的是上一次的值
    }
    const handleAdd2 = () => {
        setValue(value => value + 1)
        setTimeout(() => { console.log(`currentRef.current`, currentRef.current) }, 0);
        //获取的是最新的值
    }
    useEffect(() => {
        currentRef.current = value
    }, [value])

    return (
        <div>
            <p ref={currentRef}>current value:{value}</p>
            <button onClick={handleAdd}>+1 </button>
            <button onClick={handleAdd2}>+1(ref)</button>
        </div>
    )
})

4.2 获取上一次的state

自定义Hooks usePrevious

import React, { useEffect, useRef } from 'react'

export default function usePrevious(value) {
    const ref = useRef();
    useEffect(() => {
        ref.current = value;
        console.log(`ref.current---inner`, ref.current)
    })
    console.log(`ref.current---outer`, ref.current)
    return ref.current;
}
import React, { memo, useState } from 'react'
import usePrevious from '../usePrevious'
export default memo(function Demo1() {
    const [count, setCount] = useState(0)
    const previousCount = usePrevious(count);
    return (
        <div>
            <h3>usePrevious</h3>
            <button onClick={() => setCount(count + 1)}>+1</button>
            <button onClick={() => setCount(count - 1)}>-1</button>
            <p>Now:{count},before:{previousCount}</p>
        </div>
    )
})

原理是useEffect会在每次渲染完毕后执行,所以ref的值在本次渲染过程永远会停留在上一次。

4.3 获取dom元素的属性值

见3

你可能感兴趣的:(笔记,react)