【发布时间】:2019-08-26 02:08:23
【问题描述】:
我一直在处理 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 元素引用(只要它保持挂载,至少)。
这是因为 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 上,正如我们从上面的 sn-p 中看到的那样。
第 2 项
我可以说我在myDivElement.current 对象中得到的是HTMLElement(MDN 链接)类型之一吗?如果不是,它是什么类型/类型的对象?
第 3 项
myDivElement.current 正在初始化为 null 值。什么时候更改为div 的引用?是否在第一次渲染后发生?
额外编辑:
我做了这个额外的 sn-p 来显示一些在比较由ref 访问修改的 DOM 节点时的澄清 React 行为。
第一个按钮使用
ref直接修改DOM(切换红色和黑色),因此您会看到没有新渲染的颜色变化。当您通过更改
state强制蓝色并将其作为内联属性返回为渲染的返回时,您会立即看到它触发了重新渲染(因为它会更改蓝色状态)并且您会看到蓝色。但奇怪的是,当您再次单击第一个按钮以通过
ref更改颜色时,它再次变为红色/黑色,但现在即使您强制更新也无法将其恢复为蓝色它。它将重新渲染但不更新 DOM。由于蓝色的
state已变为true,react 将渲染结果与虚拟 DOM 中的结果进行比较(自从您第一次单击 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>
【问题讨论】:
标签: javascript html reactjs react-hooks