[英]Locking behavior of object in JS?
On every click of increment
button:每次单击
increment
按钮时:
Expectation: current count
is logged期望:记录当前
count
Reality: initial value of count
, ie 3 is logged现实:
count
的初始值,即 3 被记录
import React, { useState, useEffect } from "react";
function SomeLibrary(props) {
const [mapState, setMapState] = useState(undefined);
useEffect(() => {
console.log("setting map");
// Run exactly once at mount of component
setMapState(props.map);
}, []);
useEffect(() => {
if (mapState) {
mapState.key();
}
}, [props]);
return <div> ... </div>;
}
export default function App() {
const [count, setCount] = React.useState(3);
const map = { key: () => {
console.log("fn", count);
}};
return (
<div>
Active count: {count} <br />
<button onClick={() => {
setCount(count + 1);
}}
>
Increment
</button>
<SomeLibrary map={map} />
</div>
);
}
Does the object in JS locks the values of variables inside it after initializing? JS中的object初始化后会不会锁住里面变量的值?
I want to know the reason why function in object doesn't use the current value of count whenever invoked but React ref gets the current value in that same scenario我想知道为什么 object 中的 function 在调用时不使用 count 的当前值但 React ref 在同一场景中获取当前值的原因
I don't understand why this works:我不明白为什么会这样:
Replace the map variable with this:将 map 变量替换为:
const [count, setCount] = React.useState(3);
const stateRef = useRef();
stateRef.current = count;
const map = { key: () => {
console.log("fn", stateRef.current);
}};
No.不。
You're effectively setting state of SomeLibrary
with an initial value when it mounts, and never again updating that state, so it continually logs its initial value.您在安装时有效地将 SomeLibrary 的
SomeLibrary
设置为初始值,并且不再更新该 state,因此它会不断记录其初始值。
const [mapState, setMapState] = useState(undefined);
useEffect(() => {
console.log("setting map");
// Run only once at mount of component
setMapState(props.map); // <-- no other `setMapState` exists
}, []); // <-- runs once when mounting
By simply adding props.map
to the dependency array this effect runs only when map
updates, and correctly updates state.通过简单地将
props.map
添加到依赖数组中,此效果仅在map
更新并正确更新 state 时运行。
useEffect(() => {
console.log("setting map");
// Run only once at mount of component
setMapState(props.map);
}, [props.map]);
Notice, however, the state of SomeLibrary
is a render cycle behind that of App
.但是请注意, SomeLibrary 的
SomeLibrary
是App
之后的渲染周期。 This is because the value of the queued state update in SomeLibrary
isn't available until the next render cycle.这是因为 SomeLibrary 中排队的
SomeLibrary
更新的值在下一个渲染周期之前不可用。 It is also an anti-pattern to store passed props in local component state ( with few exceptions ).在本地组件 state 中存储传递的道具也是一种反模式(除了少数例外)。
const [count, setCount] = React.useState(3);
const stateRef = useRef();
stateRef.current = count; // <-- stateRef is a stable reference
const map = { key: () => {
console.log("fn", stateRef.current); // <-- ref enclosed in callback
}};
When react component props or state update, a re-render is triggered.当 react 组件 props 或 state 更新时,会触发重新渲染。 The
useRef
does not, it's used to hold values between or through render cycles, ie it is a stable object reference. useRef
不是,它用于在渲染周期之间或通过渲染周期保存值,即它是一个稳定的 object 参考。 This reference is enclosed in the callback function in the map object passed as a prop.此引用包含在作为道具传递的 map object 中的回调 function 中。 When the
count
state updates in App
a rerender is triggered and stateRef.current = count;
当
count
state 在App
中更新时,会触发重新渲染并且stateRef.current = count;
updates the value stored in the ref, ie this is akin to an object mutation.更新存储在 ref 中的值,即这类似于 object 突变。
Another piece to the puzzle is functional components are always rerendered when their parent rerenders.另一个难题是功能组件总是在其父级重新渲染时重新渲染。 The passed
map
object is a new object when passed in props.通过的
map
object 是一个新的 object 在通过 props 时。
It's this rerendering that allows SomeLibrary
to run the second effect to invoke the non-updated-in-state callback mapState.key
, but this time the object reference being console logged has been mutated.正是这种重新渲染允许
SomeLibrary
运行第二个效果来调用非更新状态回调mapState.key
,但是这次控制台记录的 object 引用已经发生了变异。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.