每次 Render 都有自己的 Props 与 State
可以认为每次 Render 的内容都会形成一个快照并保留下来,因此当状态变更而 Rerender 时,就形成了 N 个 Render 状态,而每个 Render 状态都拥有自己固定不变的 Props 与 State。
import React, { useRef } from "react";
import ReactDOM from "react-dom";
function MessageThread() {
const [message, setMessage] = useState("");
const showMessage = () => {
alert("You said: " + message);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = e => {
setMessage(e.target.value);
};
return (
<>
<input value={message} onChange={handleMessageChange} />
<button onClick={handleSendClick}>Send</button>
</>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<MessageThread />, rootElement);
}
如效果,点击send后修改input的值,打印出来的value依旧是原始的
利用 useRef 就可以绕过 Capture Value 的特性。可以认为 ref 在所有 Render 过程中保持着唯一引用,因此所有对 ref 的赋值或取值,拿到的都只有一个最终状态,而不会在每个 Render 间存在隔离。
function MessageThread() {
const latestMessage = useRef("");
const showMessage = () => {
alert("You said: " + latestMessage.current);
};
const handleSendClick = () => {
setTimeout(showMessage, 3000);
};
const handleMessageChange = e => {
latestMessage.current = e.target.value;
};
return (
<>
<input onChange={handleMessageChange} />
<button onClick={handleSendClick}>Send</button>
</>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<MessageThread />, rootElement);
ref跳过了Capture Value特性,打印出来的结果会和input输入框的值相同
this 在 Class Component 中是可变的,因此 this.props 的调用会导致每次都访问最新的 props。
class ProfilePage extends React.Component {
render() {
setTimeout(() => {
// 如果父组件 reRender,this.props 拿到的永远是最新的。
// 并不是 props 变了,而是 this.props 指向了新的 props,旧的 props 找不到了
console.log(this.props);
}, 3000);
}
}
而 Function Component 不存在 this.props 的语法,因此 props 总是不可变的。
function ProfilePage(props) {
setTimeout(() => {
// 就算父组件 reRender,这里拿到的 props 也是初始的
console.log(props);
}, 3000);
}