这是我的代码https://codesandbox.io/s/heuristic-cannon-lvse23?file=/src/App.js
import { useEffect, useState } from "react";
import "./styles.css";
function useAsyncState() {
const [status, setStatus] = useState("idle");
function trigger(value) {
setStatus(`sending ${value}`);
setTimeout(function () {
setStatus("done");
}, 1500);
}
return [status, trigger];
}
export default function App() {
const [value, setValue] = useState(0);
const [status, trigger] = useAsyncState();
useEffect(() => {
if (status === "done") {
setValue(value - 1);
}
}, [status, value]);
return (
<div className="App">
<p>
status: {status}
<button onClick={() => trigger(value)}>send & decrement</button>
</p>
<p>
value: {value}
<button onClick={() => setValue(value + 1)}>increment</button>
</p>
</div>
);
}
我将某种异步操作 Package 到了一个定制钩子useAsyncState
中(来自我的依赖项的一些真实的钩子的简化版本)。
问题是,我只想更新value
一次,当异步操作变成done
状态时。
然而,改变状态重新呈现组件,并且由于status
仍然是done
,因此value
再次改变,导致递减的无限循环。
此外,动作可以再次触发,我想递减值,当它再次done
。
如果我有一个原始的Promise,我可以在then
回调中完成,但我只有这样的钩子。
另外,使用useEffect
会延迟value
更新到下一个渲染,所以需要两个渲染来显示减少的value
。这不是什么大问题,但在单个渲染中完成它会很好。
有没有可能用这样一个自定义的钩子做得很好?或者使用原始的承诺是唯一的方法?
1条答案
按热度按时间rqqzpn5f1#
您可以改用功能更新:
如果新的状态是使用先前的状态计算出来的,你可以传递一个函数给setState。这个函数将接收先前的值,并返回一个更新的值。