React钩子useRef()如何在后台运行?那个参考到底是什么?

时间:2019-04-04 10:42:38

标签: javascript html reactjs react-hooks

我一直在处理React钩子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 Docs,我们知道在每个渲染上都会得到相同的对象。因此,我在每个渲染器上都得到了html元素的相同引用(至少要保持挂载)。

From React Docs

  

之所以有效,是因为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.current对象中得到的是类型HTMLElement(MDN链接)之一吗?如果不是,那是什么种类/类型的物体?

项目3

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

额外编辑:

我做了这个额外的代码片段,以展示一些澄清的React行为,用于比较通过ref访问修改的DOM节点。

  • 第一个按钮使用ref直接修改DOM(切换红色和黑色),因此您会看到颜色变化而没有新的渲染。

  • 当您通过state中的更改强制蓝色并将其作为内联属性作为渲染的返回值返回时,您立即看到它触发了重新渲染(因为它会更改蓝色状态),并且您会看到蓝色。

  • 但是奇怪的是,当您再次单击第一个按钮以通过ref更改颜色时,它再次变为红色/黑色,但是现在即使您将其恢复为蓝色,也无法将其恢复为蓝色。强制更新它。它将重新渲染而不更新DOM。

  • 由于蓝色的state变成了true,react将渲染结果与虚拟DOM中的渲染结果进行比较(自第一次单击“强制蓝色”以来一直为蓝色) ),然后返回相等的节点。它不知道DOM实际上是红色的,因为您已经直接通过ref进行了更改。

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>

1 个答案:

答案 0 :(得分:3)

  

引用myDivElement.current所指的是什么

myDivElement.current收到对基础DOM元素的引用

  

我可以说我在myDivElement.current对象中得到的是   输入HTMLElement

将ref分配给div元素时,myDivElement.current的类型为HTMLDivElement

  

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

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