likes
comments
collection
share

React-Hooks 初识 (三): useRef 的使用:获取DOM元素和保存变量

作者站长头像
站长
· 阅读数 66

写在前面:万年鸽王回来了😁😁😁,记得我上次更文还是在上次。本想着过完年好好输出输出,结果这一歇就把人歇懒了。害,还是要时刻保持学习呐,更文不能停!!! 上一篇useEffect里我说了要解释下capture value 特性,这个其实一句话来说就是拿了 props或者state的快照,导致每次要做处理的时候都是用的某一刻state的快照在处理,这样就导致我们获取不到最新的值来进行更新页面。解决办法也简单:一种是加依赖项;另一种就是利用本篇useRef的一个特性:在任一地方取useRef保存的值都是取最新的!!好了,废话不多说,进入本次useRef的学习🐻‍🐰

React-Hooks 初识 (三): useRef 的使用:获取DOM元素和保存变量

const refContainer = useRef(initialValue);

useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变。


补充: useRef 设定的值进行重新赋值时是不会引发组件的重新渲染的。如果变量不涉及页面展示只是用来查询值时,此变量就可以用 useRef 进行保存;例如:在进行数据请求时,我们往往要进行处理入参,此时入参就可以用useRef进行保存。有小伙伴可能会问为什么不用state来进行设置。这里我们要注意区分何时用state--->若我们设置的变量是需要在页面渲染展示的、或者我们设置的此值变化要引起重新渲染时,我们再使用useState。否则,引入太多state会造成不必要的rerender。

1 useRef 的作用

  • 用useRef获取React JSX中的DOM元素,获取后你就可以控制DOM的任何东西了。

  • 用useRef来保存变量,注意:useRef 每次都会返回相同的引用

  • 可以用来生成对 DOM 对象的引用。

2 useRef 获取DOM 元素

需求说明:界面上有一个文本框,在文本框的旁边有一个按钮,当我们点击按钮时,在控制台打印出input的DOM元素,并进行复制到DOM中的value上。这一切都是通过useRef来实现。

demo1:  这段代码的实现的功能就是点击button按钮将input框里输入的值展示到p标签内。
import React, { useState, useRef } from "react";
function App() {
  let [name, setName] = useState("Nate");
  let nameRef = useRef(); // 这里就是获取ref绑定的那个DOM元素值
  const submitButton = () => {
    setName(nameRef.current.value);     / 这里用setName设置name值时,是把input框里的输入值传入进去
  };
  return (
    <div className="App">
      <p>{name}</p>
 
      <div>
        <input ref={nameRef} type="text" />     / 这里的ref就是获取了这个input输入框,利用ref.current就可以获取这个DOM节点
        <button type="button" onClick={submitButton}>
          Submit
        </button>
      </div>
    </div>
  );
}
=====================================================================
demo2: 使用 useRef 创建的变量指向一个 input 元素,点击按钮后使 input 聚焦
  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>
    </>
  );
}

代码分析:useRef 返回的值传递给组件或者 DOM 的 ref 属性,就可以通过 ref.current 值访问组件或真实的 DOM 节点,从而可以对 DOM 进行一些操作,比如监听事件等等。这个利用useRef获取DOM元素的操作可以类比vue中利用ref属性进行相应的获取DOM元素或组件进行理解;

3  利用useRef 保存普通变量

代码片段

demo1: 利用useRef保存值
import React, { useRef, memo } from 'react';
const InnerTable = memo(function (props) {
const queryRef = useRef({
        invoiceCode: '',
        invoiceNumber: '',
    });
  
  
  return (
  <input  onChange={(e)=>{queryRef.current.invoiceCode=e.target.value}} placeholder="请输入发票代码"> </input>
     <input  onChange={(e)=>{queryRef.current.invoiceNumber=e.target.value}} placeholder="请输入发票号码"> </input>
  )
})

这时候就可以实现每次状态修改,同时保存到useRef中了。也就是我们说的保存变量的功能。

3.1 useRef 可以绕过Capture Value 的特性 (非常重要): 也就是说,ref不会受到闭包影响,声明过ref后,在之后拿此ref值时拿到的都是最新的ref

注意: useRef 在 react hook 中的作用,就像一个盒子, 你可以存放任何东西,useRef 每次都会返回相同的引用;利用 useRef 可以绕过React Hooks 中的 Capture Value 的特性,可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最新状态,而不会在每个 Render 间存在快照。

注意 :React Hooks 中存在 Capture Value 的特性:

function MessageDemo() {
  const [message, setMessage] = useState("");
 
  const showMessage = () => {
    alert("You said: " + message);
  };
 
  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };
 
  const handleMessageChange = e => {
    setMessage(e.target.value);
  };
 
  return (
    <>
      <input value={message} onChange={handleMessageChange} />
      <button onClick={handleSendClick}>Send</button>
    </>
  );
}

对Capture Value 特性的分析:在点击 Send 按钮后,再次修改输入框的值,3 秒后的输出依然是点击前输入框的值。这就是所谓的 capture value 的特性。而在类组件中不会出现这种情况,在 3 秒后输出的就是修改后的值,因为这时候 message 是挂载在 this 变量上,它保留的是一个引用值,对 this 属性的访问都会获取到最新的值。此时我们可以用 useRef 来创建一个引用,就可以有效规避 React Hooks 中 Capture Value 特性。

function MessageThread() {
  const latestMessage = useRef("");
 
  const showMessage = () => {
    alert("You said: " + latestMessage.current);
  };
 
  const handleSendClick = () => {
    setTimeout(showMessage, 3000);
  };
 
  const handleMessageChange = e => {
    latestMessage.current = e.target.value;   // 这里就是赋值取值对象变为useRef
  };
}

只要将赋值与取值的对象变成 useRef,而不是 useState,就可以躲过 capture value 特性,在 3 秒后得到最新的值。

补充: 当我们使用useRef来保存值时,一定要注意初始值设置里不能用函数来进行赋值,因为这样会造车每次render此函数都会执行。下面请看demo

 const formatData = () => {
        console.log('执行了');
        return ‘初始值’
    };
 const testRef = useRef(formatData());    每次 rerender 这个formData函数都会执行;为避免这种情况我们可以使用useEffect设置初始值;  或者直接使用useMemo
转载自:https://juejin.cn/post/7071998820225122335
评论
请登录