首先,“重新渲染”在这里指的是:
“重新渲染”的规则是否就如此简单呢?
- 调用任何类组件的
render()
方法,或 - 调用函数组件的函数。
“重新渲染”的规则是否就如此简单呢?
像这样就行了吗?例如:当组件的任何状态发生改变时,该组件及从该组件向下的所有子树都将被重新渲染。
function A() {
console.log("Component A re-render");
return <div>Component A says Hello World</div>;
}
function App() {
const [counter, setCounter] = React.useState(0);
console.log("Component App re-render");
function increaseCount() {
setCounter(c => c + 1);
}
return (
<div>
{counter}
<button onClick={increaseCount} >Increment</button>
<A />
</div>
)
}
ReactDOM.render(<App />, document.querySelector("#root"));
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
组件A非常简单:它甚至不需要任何props,仅输出静态文本,但是每次仍然被调用(通过查看console.log()
输出可以看到)。
但是即使它被“重新渲染”,实际的DOM元素也没有被“刷新”,如Google Chrome的Inspect Element所示,对于组件A,DOM元素没有闪烁,但只有计数器数字在闪烁。
那么它是如何工作的呢?
- 无论何时更改组件的任何状态,该组件及其整个子树都将被“重新渲染”。
- 但是ReactJS将使用那些JSX构建的“虚拟DOM”的内容与实际DOM的内容进行“协调”,如果内容不同,则“刷新实际DOM”。
但是话虽如此,似乎ReactJS并没有真正与实际DOM协调,而是与可能的“先前虚拟DOM”协调。为什么? 因为如果我在3秒后使用setTimeout()
将组件A的实际DOM更改为其他内容,并单击按钮,ReactJS不会将组件A的内容更改回“Hello World”。例如:
function A() {
console.log("Component A re-render");
return <div id="foo">Component A says Hello World</div>;
}
function App() {
const [counter, setCounter] = React.useState(0);
console.log("Component App re-render");
function increaseCount() {
setCounter(c => c + 1);
}
return (
<div>
{counter}
<button onClick={increaseCount} >Increment</button>
<A />
</div>
)
}
ReactDOM.render(<App />, document.querySelector("#root"));
setTimeout(function() {
document.querySelector("#foo").innerText = "hi"
}, 3000);
<script src="https://unpkg.com/react@16.12.0/umd/react.development.js" crossorigin></script>
<script src="https://unpkg.com/react-dom@16.12.0/umd/react-dom.development.js" crossorigin></script>
<div id="root"></div>
document.getElementById("B").firstChild = "abc"
更改文本节点,如果我在#B
下创建两个子节点,它仍然不会更新,所以看起来 React 记住了第二个文本节点并更新它,而它已经不在屏幕上了。 - nonopolaritydocument.getElementById("B").firstChild.nodeValue = "Hi B"; document.getElementById("B").firstChild.nextSibling.nodeValue = "Hi B";
,而React可以更新第二个节点...所以看起来React也使用node.nodeValue
来更改文本节点的内容。 - nonopolarity