英文:
Why do I get old useRef() value?
问题
我创建了一个钩子,其目的是将樱桃添加到一个数组中:
然后我在按钮点击时调用它:
我不明白为什么在调用dispatchCherry()
之后cherryRef.current
会返回旧值。理论上,它应该返回增加后的值,因为myRef
是一个对象。
我试图在调用dispatch()
之后立刻获取增加后的值。
英文:
I created a hook, whose purpose is adding cherries to an array:
import { useReducer, useRef } from "react";
const useCherry = () => {
const myRef = useRef(0);
const [state, dispatch] = useReducer(
(state, action) => {
if (action.type === "add") {
myRef.current += 1;
return [...state, "🍒"];
}
return state;
},
[]
);
return [state, dispatch, myRef];
};
export default useCherry;
Then I call it on button click:
<button
type="button"
onClick={() => {
console.log(myRef.current); // Logs 0
dispatch({ type: "add" });
console.log(myRef.current);// Logs 0, expected 1
}}
>
Add more cherry
</button>
I don't understand why would cherryRef.current
return an old value after calling dispatchCherry()
. In theory it should return the incremented one, as myRef
is an object.
I'm trying to get the incremented value right after calling the dispatch()
.
答案1
得分: 3
因为 dispatch()
运行并更新下一次渲染的状态,第二个 console.log()
在它之前运行,因此返回旧值。
要在更改前后分别存储和检索 useRef
值(在 state
之外),考虑导出一个自定义的 dispatch()
供另一个组件使用。
const myDispatchCherry = (action) => {
if (action?.type === "add") myRef.current += 1;
dispatch(action);
}
这还可以使原始的 dispatch()
保持纯净,并将附加任务作为可选的可定制部分添加。
在这里测试以下代码:stackblitz
import React, { useReducer, useRef } from "react";
const useCherry = () => {
const myRef = useRef(0);
const [state, dispatch] = useReducer(
(state, action) => {
if (action.type === "add") {
return [...state, "🍒"];
}
return state;
},
[]
);
const myDispatchCherry = (action) => {
if (action?.type === "add") myRef.current += 1;
dispatch(action);
}
return {state, dispatch, myRef, myDispatchCherry};
};
export default useCherry;
export default function App() {
const {state, myRef, myDispatchCherry} = useCherry();
return (
<div>
<p>{`Cherry: ${state}`}</p>
<button
type="button"
onClick={() => {
console.log(`myRef count before adding: ${myRef.current}`); // Logs 0
myDispatchCherry({ type: "add" });
console.log(`myRef count after adding: ${myRef.current}`); // Logs 1
}}
>
Add more cherry
</button>
</div>
);
}
英文:
Because dispatch()
runs and updates the state for the next render, the second console.log()
runs before it, and thus returns the old value.
To store and retrieve the useRef
value before and after the change separately (outside of the state
), consider to export a customized dispatch()
for use in another component.
const myDispatchCherry = (action) => {
if (action?.type === "add") myRef.current += 1;
dispatch(action);
}
This could also keep the original dispatch()
pure to its function, and add the additional tasks as an optional and customizable part.
Test the follow code here: stackblitz
import React, { useReducer, useRef } from "react";
const useCherry = () => {
const myRef = useRef(0);
const [state, dispatch] = useReducer(
(state, action) => {
if (action.type === "add") {
return [...state, "🍒"];
}
return state;
},
[]
);
const myDispatchCherry = (action) => {
if (action?.type === "add") myRef.current += 1;
dispatch(action);
}
return {state, dispatch, myRef, myDispatchCherry};
};
export default useCherry;
export default function App() {
const {state, myRef, myDispatchCherry} = useCherry();
return (
<div>
<p>{`Cherry: ${state}`}</p>
<button
type="button"
onClick={() => {
console.log(`myRef count before adding: ${myRef.current}`); // Logs 0
myDispatchCherry({ type: "add" });
console.log(`myRef count after adding: ${myRef.current}`); // Logs 1
}}
>
Add more cherry
</button>
</div>
);
}
答案2
得分: 0
> 我不明白为什么在调用 dispatchCherry() 后,cherryRef.current 会返回一个旧值,理论上它应该返回递增的值,因为 myRef 是一个对象。
是的,它确实返回了递增的值,但由于它尚未完成重新渲染的触发,所以不会立即显示给您(因为 useRef 不完全是状态变量)。可以使用 useState/useReducer 钩子来手动触发,或者您可以将 myRef 更改为状态变量。
例如,这可以给您下一个更新的值:
dispatch({ type: "add" });
setTimeout(() => {
console.log(cherryRef.current); // 输出 1
}, 0);
英文:
> I don't understand why would cherryRef.current return an old value
> after calling dispatchCherry(). In theory it should return the
> incremented one, as myRef is an object.
Yes, it does return the incremented value, but since it does not complete the trigger of a re-render yet, it is not shown to you (because useRef
is not exactly a state variable). The useState/useReducer
hook can be used to manually trigger, or you can change myRef
to a state variable.
Example, this can give you next updated value:
dispatch({ type: "add" });
setTimeout(() => {
console.log(cherryRef.current); // Logs 1
}, 0);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论