我正在尝试使用钩子来存储状态。该钩子公开了对该值的引用和一个简单的mutator函数。我想有一个不同的更新器挂钩,它使用所说的增幅器。虽然在更新程序中该值是正确的,但是如果我还有另一个钩子,则该值始终是初始值。这是重现该问题的示例。
import React, { useEffect, useRef } from "react";
function useCounter() {
const counter = useRef<number>(0);
const increment = () => {
counter.current++;
};
return [counter, increment] as const;
}
function useUpdate() {
const [counter, increment] = useCounter();
console.log("rendering update");
return () => {
increment();
console.log(counter.current);
};
}
function useLoop() {
const update = useUpdate();
const [counter] = useCounter();
console.log("rendering loop");
return () => {
update();
console.log(counter.current);
};
}
export default function App() {
const loop = useLoop();
useEffect(() => {
const id = window.setInterval(loop, 1000);
return () => {
window.clearInterval(id);
};
}, [loop]);
return <div />;
}
在useUpdate内部,计数器的值是正确的,但是在useLoop内部,其值始终为0。我使用的是ref,因为当计数器发生变化并且因为它是一个对象时,不需要重新运行挂钩,从循环返回的函数应该通过引用来接受它,并且必须始终具有最新的值,但事实并非如此。 我的目标是使用类似的模式来编写与p5js结合的模拟。这个问题与p5根本无关,所以我只是嘲笑了它的更新功能。 我尝试使用useState,useCallback,但没有任何效果。
我是钩子的新手,这种模式可能是完全错误的。我欢迎使用钩子进行高级分解的提示。
谢谢!
编辑:
问题是useCounter运行两次并创建两个不同的不相关实例。这是我提出的状态分解解决方案:
import React, { useEffect, useRef } from "react";
function useCounter() {
const counter = useRef<number>(0);
const increment = () => {
counter.current++;
};
return { counter, increment };
}
function useUpdate({ counter, increment }) {
console.log("rendering update");
return () => {
increment();
console.log(counter.current);
};
}
function useLoop(state) {
const update = useUpdate(state);
console.log("rendering loop");
return () => {
update();
console.log(state.counter.current);
};
}
export default function App() {
const state = useCounter();
const loop = useLoop(state);
useEffect(() => {
const id = window.setInterval(loop, 1000);
return () => {
window.clearInterval(id);
};
}, [loop]);
return <div />;
}
答案 0 :(得分:1)
在useLoop
中,您实例化了counter
的新版本,该版本与之前声明的版本不同。
要解决此问题,您需要从counter
返回useUpdate
,以便:
function useUpdate() {
const [counter, increment] = useCounter();
console.log("rendering update");
const incrementFunc = () => {
increment();
console.log(counter.current);
};
return [incrementFunc, counter]
}
function useLoop() {
const [update, counter] = useUpdate();
// const [counter] = useCounter(); this will be a new counter
console.log("rendering loop");
return () => {
update();
console.log(counter.current);
};
}
答案 1 :(得分:0)
我认为这是一个范围问题。您可以在useLoop中初始化一个新的计数器变量,该变量独立于useUpdate中的变量。您必须从挂钩中同时返回变量及其mutator函数。我对useUpdate和useLoop挂钩进行了以下更改,它似乎按预期运行。
function useUpdate() {
const [counter, increment] = useCounter();
console.log("rendering update");
// return both counter and its mutator function
return [counter, () => {
increment();
console.log(counter.current);
}];
}
function useLoop() {
// use counter variable exported from useUpdate hook
const [counter, update] = useUpdate();
console.log("rendering loop");
return () => {
update();
console.log(counter.current);
};
}
不确定这是否有帮助,我对Hooks还是陌生的,也许有更多经验的人可以回答得更好。