我一直在处理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元素的相同引用(至少要保持挂载)。
之所以有效,是因为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.current
用null
值初始化。什么时候更改为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>
答案 0 :(得分:3)
引用
myDivElement.current
所指的是什么
myDivElement.current
收到对基础DOM元素的引用
我可以说我在
myDivElement.current
对象中得到的是 输入HTMLElement
将ref分配给div元素时,myDivElement.current
的类型为HTMLDivElement
myDivElement.current
正在使用空值初始化。什么时候 更改为div的引用?第一次发生后 渲染?
在第一次渲染期间,将在创建ref对象时将其分配给DOMNode。对DOM节点的更新也会导致对象发生变化