首页 > 解决方案 > React 钩子 useRef() 如何在幕后工作?那个参考到底是什么?

问题描述

我一直在处理 React hook useRef() 的一些问题,我想这是因为我还没有真正掌握它的概念和功能。

我知道它可以用作函数范围之外的“全局”变量。所以下面的计数器工作得很好。我只需要强制更新它,因为更改myCounter.current属性本身不会触发重新渲染。

const { useState, useRef } = React;

function App() {

  const myCounter = useRef(0);
  const [forceUpdate,setForceUpdate] = useState(true);
  
  const handleClick = (e) => {
    myCounter.current+=1;
    setForceUpdate((prev)=>!prev);
  }

  return (
    <div>
      <div>{myCounter.current}</div>
      <button onClick={handleClick}>Click</button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

当我使用它来存储 HTML 元素的引用时,我的怀疑就开始了。从下面的 React 文档中,我们知道每次渲染都会得到相同的对象。所以我在每次渲染时都得到了相同的 html 元素引用(只要它保持挂载,至少)。

来自 React 文档

这是因为 useRef()创建了一个普通的 JavaScript 对象。useRef() 和自己创建 {current: ...} 对象之间的唯一区别是useRef 将在每次渲染时为您提供相同的 ref 对象。

例如:

const { useState, useRef } = React;

function App() {

  const myDivElement = useRef(null);
  
  const [forceUpdate,setForceUpdate] = useState(true);
  
  const handleClick = (e) => {
    if (myDivElement.current.style.color === 'red') {
      myDivElement.current.style.color='black';  
    }
    else {
      myDivElement.current.style.color='red';
    }
    setForceUpdate((prev)=>!prev);
  }

  return (
    <div>
      <div ref={myDivElement}><b>Some content inside my Div element</b></div>
      <button onClick={handleClick}>Click</button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

注意:我知道在这里提出多个问题并不是最佳做法。但这更像是一种概念性的,理解以下项目将真正帮助我完全掌握这个钩子的功能。

项目 1

参考myDivElement.current到底指向什么?它是否指向虚拟 DOM 中该元素的节点对象?因为我知道,例如,当我更改它的 CSS 属性时,我会看到该更改反映在 DOM 上,正如我们从上面的代码片段中看到的那样。

第 2 项

我可以说我在myDivElement.currentobject 中得到的是HTMLElement (MDN link) 类型之一吗?如果不是,它是什么类型/类型的对象?

第 3 项

myDivElement.current正在用null值初始化。什么时候更改为 的引用div?第一次渲染后会发生吗?

额外编辑:

ref我制作了这个额外的片段,以显示在比较通过访问修改的 DOM 节点时的一些澄清 React 行为。

const { useState, useRef } = React;

function App() {

  const myDivElement = useRef(null);
  
  const [blue,setBlue] = useState(false);
  
  const [forceUpdate,setForceUpdate] = useState(true);
  
  const renderTimes = useRef(0);
  
  renderTimes.current+=1;
  
  const handleClick = (e) => {
    if (myDivElement.current.style.color === 'red') {
      myDivElement.current.style.color='black';  
    }
    else {
      myDivElement.current.style.color='red';
    }
    //setForceUpdate((prev)=>!prev);
    //setBlue(false);
  }
  
  const handleClick2 = (e) => {
    setForceUpdate((prev)=>!prev);
    // setBlue(false);
  }
  
  const handleClick3 = (e) => {
    setBlue(true);
  }

  const divStyle = {
  color: 'blue',
  };

  return (
    <div>
      <div ref={myDivElement} style={{ color: blue? 'blue' : 'initial'}}><b>Some content inside my Div element</b></div>
      <p>I was rendered {renderTimes.current} time(s)</p>
      <button onClick={handleClick}>Toggle Color with useRef()</button>
      <button onClick={handleClick2}>Force Update</button>
      <button onClick={handleClick3}>Force Blue as inline style</button>
    </div>
  );
}

ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>

<div id="root"></div>

标签: javascripthtmlreactjsreact-hooks

解决方案


参考myDivElement.current到底指的是什么

myDivElement.current接收对底层 DOM 元素的引用

我可以说我在myDivElement.currentobject 中得到的是 HTMLElement 类型之一

当您将 ref 分配给 div 元素时,myDivElement.current它将是HTMLDivElement类型

myDivElement.current正在使用空值初始化。什么时候改变 div 的引用?第一次渲染后会发生吗?

在第一次渲染期间,ref 对象在创建时被分配给 DOMNode。对 DOM 节点的更新也会导致对象发生变化


推荐阅读