React hook useRef() 是如何工作的?那个参考到底是什么?
How does React hook useRef() work under the hood? What is that reference exactly?
我一直在处理 React hook useRef() 的一些问题,我想这是因为我还没有真正掌握它的概念和功能。
我知道它可以用作函数范围之外的 'global' 变量。所以下面的计数器工作得很好。我只需要强制更新它,因为更改 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 元素引用(只要它保持挂载,至少)。
This works because useRef() creates a plain JavaScript object. The
only difference between useRef() and creating a {current: ...} object
yourself is that useRef will give you the same ref object on every
render.
例如:
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 link) 类型之一吗?如果不是,它是什么kind/type对象?
项目 3
myDivElement.current
正在用 null
值初始化。什么时候更改为 div
的引用?它会在第一次渲染后发生吗?
额外编辑:
我制作了这个额外的代码片段,以在比较 ref
访问修改的 DOM 节点时显示一些明确的 React 行为。
第一个按钮使用 ref
直接修改 DOM(切换红色和黑色),因此您会看到没有新渲染的颜色变化。
当您通过 state
和 return 中的更改强制蓝色作为渲染的 return 的内联属性时,您会立即看到它触发了重新渲染(因为它改变了蓝色状态)并且你看到了蓝色。
但是奇怪的是,当你再次点击第一个按钮通过ref
改变颜色时,它又变成了red/black,但是现在你无法得到它即使您强制更新它,它也会变回蓝色。它会重新渲染但不会更新 DOM.
由于蓝色state
变成了true
,react将render的结果与virtualDOM中的结果进行比较(从那以后一直是蓝色的您第一次单击 Force Blue)并作为相等节点返回。它不知道 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>
What does the reference myDivElement.current
points to exactly
myDivElement.current
接收对底层 DOM 元素的引用
Can I say that what I get in myDivElement.current
object is one of the
type HTMLElement
当您将 ref 分配给 div 元素时,myDivElement.current
的类型将为 HTMLDivElement
myDivElement.current
is being initialized with null value. When does
that change to the reference of the div? Does it happen after 1st
render?
在第一次渲染期间,ref 对象在创建时被分配给 DOMNode。 DOM 节点的更新也会导致对象发生变化
我一直在处理 React hook useRef() 的一些问题,我想这是因为我还没有真正掌握它的概念和功能。
我知道它可以用作函数范围之外的 'global' 变量。所以下面的计数器工作得很好。我只需要强制更新它,因为更改 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 元素引用(只要它保持挂载,至少)。
This works because useRef() creates a plain JavaScript object. The only difference between useRef() and creating a {current: ...} object yourself is that useRef will give you the same ref object on every render.
例如:
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 link) 类型之一吗?如果不是,它是什么kind/type对象?
项目 3
myDivElement.current
正在用 null
值初始化。什么时候更改为 div
的引用?它会在第一次渲染后发生吗?
额外编辑:
我制作了这个额外的代码片段,以在比较 ref
访问修改的 DOM 节点时显示一些明确的 React 行为。
第一个按钮使用
ref
直接修改 DOM(切换红色和黑色),因此您会看到没有新渲染的颜色变化。当您通过
state
和 return 中的更改强制蓝色作为渲染的 return 的内联属性时,您会立即看到它触发了重新渲染(因为它改变了蓝色状态)并且你看到了蓝色。但是奇怪的是,当你再次点击第一个按钮通过
ref
改变颜色时,它又变成了red/black,但是现在你无法得到它即使您强制更新它,它也会变回蓝色。它会重新渲染但不会更新 DOM.由于蓝色
state
变成了true
,react将render的结果与virtualDOM中的结果进行比较(从那以后一直是蓝色的您第一次单击 Force Blue)并作为相等节点返回。它不知道 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>
What does the reference
myDivElement.current
points to exactly
myDivElement.current
接收对底层 DOM 元素的引用
Can I say that what I get in
myDivElement.current
object is one of the type HTMLElement
当您将 ref 分配给 div 元素时,myDivElement.current
的类型将为 HTMLDivElement
myDivElement.current
is being initialized with null value. When does that change to the reference of the div? Does it happen after 1st render?
在第一次渲染期间,ref 对象在创建时被分配给 DOMNode。 DOM 节点的更新也会导致对象发生变化