useRef 保存引用值和useImperativeHandle 透传 Ref

Posted 前端e站

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了useRef 保存引用值和useImperativeHandle 透传 Ref相关的知识,希望对你有一定的参考价值。

上一节我们介绍了useCallback 记忆函数和useMemo 记忆组件,这一节来学习一下useRef 保存引用值和useImperativeHandle 透传 Ref。 

useRef 保存引用值

useRef 跟 createRef 类似,都可以用来生成对 DOM 对象的引用,看个简单的例子:

import React,  useState, useRef  from "react";
function App() 
  let [name, setName] = useState("Nate");
  let nameRef = useRef();
  const submitButton = () => 
    setName(nameRef.current.value);
  ;
  return (
    <div className="App">
      <p>name</p>
 
      <div>
        <input ref=nameRef type="text" />
        <button type="button" onClick=submitButton>
          Submit
        </button>
      </div>
    </div>
  );

 useRef 返回的值传递给组件或者 DOM 的 ref 属性,就可以通过 ref.current 值访问组件或真实的 DOM 节点,重点是组件也是可以访问到的,从而可以对 DOM 进行一些操作,比如监听事件等等。

当然 useRef 远比你想象中的功能更加强大,useRef 的功能有点像类属性,或者说您想要在组件中记录一些值,并且这些值在稍后可以更改。

利用 useRef 就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。

参考例子:精读《Function VS Class 组件》

React Hooks 中存在 Capture Value 的特性:

function App() 
  const [count, setCount] = useState(0);
 
  useEffect(() => 
    setTimeout(() => 
      alert("count: " + count);
    , 3000);
  , [count]);
 
  return (
    <div>
      <p>You clicked count times</p>
      <button onClick=() => setCount(count + 1)>增加 count</button>
      <button onClick=() => setCount(count - 1)>减少 count</button>
    </div>
  );

 先点击增加button,后点击减少button,3秒后先alert 1,后alert 0,而不是alert两次0。这就是所谓的 capture value 的特性。而在类组件中 3 秒后输出的就是修改后的值,对 this 属性的访问都会获取到最新的值,类组件举例,在线Demo。讲到这里你应该就明白了,useRef 创建一个引用,就可以有效规避 React Hooks 中 Capture Value 特性。

useRef避免 Capture Value

function App() 
  const count = useRef(0);
 
  const showCount = () => 
    alert("count: " + count.current);
  ;
 
  const handleClick = number => 
    count.current = count.current + number;
    setTimeout(showCount, 3000);
  ;
 
  return (
    <div>
      <p>You clicked count.current times</p>
      <button onClick=() => handleClick(1)>增加 count</button>
      <button onClick=() => handleClick(-1)>减少 count</button>
    </div>
  );

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

useImperativeHandle 透传 Ref

通过 useImperativeHandle 用于让父组件获取子组件内的索引。

import React,  useRef, useEffect, useImperativeHandle, forwardRef  from "react";
function ChildInputComponent(props, ref) 
  const inputRef = useRef(null);
  useImperativeHandle(ref, () => inputRef.current);
  return <input type="text" name="child input" ref=inputRef />;

const ChildInput = forwardRef(ChildInputComponent);
function App() 
  const inputRef = useRef(null);
  useEffect(() => 
    inputRef.current.focus();
  , []);
  return (
    <div>
      <ChildInput ref=inputRef />
    </div>
  );

通过这种方式,App 组件可以获得子组件的 input 的 DOM 节点。

关注我,下一节一起学习useEffect和useLayoutEffect有什么区别?。

以上是关于useRef 保存引用值和useImperativeHandle 透传 Ref的主要内容,如果未能解决你的问题,请参考以下文章

useRef 保存引用值和useImperativeHandle 透传 Ref

在 React-Hooks UseRef 我无法获得新的状态值

useEffect和useLayoutEffect有什么区别?

useEffect和useLayoutEffect有什么区别?

useEffect和useLayoutEffect有什么区别?

我可以使用 useRef 将对元素的引用传递给孩子吗?