Javascript 带有自定义react钩子的过时状态
Javascript 带有自定义react钩子的过时状态,javascript,reactjs,react-hooks,Javascript,Reactjs,React Hooks,const rootElement=document.getElementById(“根”); ReactDOM.render( , 根元素 ) 函数平方(n,超时=1000){ 返回新承诺((解决、拒绝)=>{ setTimeout(()=>resolve(n*n),timeout); }); } 函数App(){ const[number,setNumber]=React.useState(0); 常量[加载、结果、错误、重新加载]=UseAncy( ()=>正方形(数字,1000), [数
const rootElement=document.getElementById(“根”);
ReactDOM.render(
,
根元素
)
函数平方(n,超时=1000){
返回新承诺((解决、拒绝)=>{
setTimeout(()=>resolve(n*n),timeout);
});
}
函数App(){
const[number,setNumber]=React.useState(0);
常量[加载、结果、错误、重新加载]=UseAncy(
()=>正方形(数字,1000),
[数字]
);
控制台日志(编号、结果);
返回(
减量{“}
setNumber(number=>setNumber(number-1))}
>
-
编号:{Number}
其平方:{result}{loading&&}
增量
setNumber(number=>setNumber(number+1))}
>
+
);
}
函数useAncy(func,dependencyArray=[]){
常量[状态,设置状态]=React.useState({
加载:false,
结果:空,
错误:null,
是的
});
常量重新加载=()=>{
函数调用(){
设置状态(状态=>({
……国家,
加载:对,
错误:null,
结果:空
}));
func()
。然后(res=>{
如果(!state.mounted)返回;
设置状态(状态=>({
……国家,
结果:res,,
加载:错误
}));
})
.catch(错误=>{
设置状态(状态=>({
……国家,
加载:false,
结果:空,
错误
}));
})
}
call();
};
React.useffect(()=>{
重新加载();
return()=>
设定状态({
……国家,
加载:false,
结果:空,
错误:null
});
},依赖数组);
React.useffect(()=>{
setState(state=>({…state,mounted:true}));
return()=>setState(state=>({…state,mounted:false}));
}, []);
返回[state.loading,state.result,state.error,reload,setState];
}
.App{
字体系列:无衬线;
文本对齐:居中;
显示器:flex;
调整内容:灵活启动;
调整项目:灵活启动;
弯曲方向:立柱;
}
钮扣{
宽度:100px;
高度:40px;
边界半径:4px;
}
您在控制台中看到null,因为当数字更改时,您正在重置自定义挂钩内的状态,使其在重载函数以及useEffect的清除函数中具有
result=null
const reload = () => {
async function call() {
try {
setState(state => ({
...state,
loading: true,
error: null,
result: null
}));
const res = await func();
if (!state.mounted) return;
setState(state => ({
...state,
result: res,
loading: false
}));
} catch (error) {
if (!state.mounted) return;
setState(state => ({
...state,
loading: false,
result: null,
error
}));
}
}
call();
};
如果您不想将值重置为null,并且只在计算完成后更新它,那么可以避免重置值,但我建议您继续执行您所做的操作,因为它可以更好地处理场景,并且由于您已将状态加载设置为true,因此您可以显示加载程序,直到获取结果
但是,您可以删除useEffect的清除函数中的setState,这是不需要的
const reload = () => {
async function call() {
try {
setState(state => ({
...state,
loading: true,
}));
const res = await func();
if (!state.mounted) return;
setState(state => ({
...state,
result: res,
loading: false
}));
} catch (error) {
if (!state.mounted) return;
setState(state => ({
...state,
loading: false,
result: null,
error
}));
}
}
call();
};
React.useEffect(() => {
reload();
}, dependencyArray);
当您多次单击递增或递减按钮时,您有多个未兑现的承诺。然后,
result
只是随着每个承诺的解决而更新
如果您主要关心的是确保用户没有看到不正确的结果,则可以让传递的函数返回一个包含原始参数和答案的数组,然后检查以确保number
的当前值与之匹配:
function square(n, timeout = 1000) {
return new Promise((resolve, reject) => {
setTimeout(() => resolve([n, n * n]), timeout);
});
}
export default function App() {
const [number, setNumber] = useState(0);
const [loading, argAndResult, error, reload] = useAsync(
() => square(number, 1000),
[number]
);
if (argAndResult && argAndResult[0] === number)
{ result = argAndResult[1]; }
else { result = null; }
虽然不理想,但在某些使用情况下仍能正常工作。感谢您提供有用的链接@T.J.Crowder。我已经做了适当的修改。谢谢你的回答@shubham。但是null完全是故意的,不是bug。当我的应用程序打印34时,这是一个错误,因为4是2的平方,这是以前的状态。我已经创建了工作代码段。请跑过去看看。错误只在控制台中可见。我看不到它在任何时候打印34当数字设置为2时,你增加它,它将打印34。请先把数字增加到2。然后再增加一次。您将看到3 4。这是因为UseAncy中的useEffect只有在更改了数字后才会触发,因此会使用大于useEffect的递增数字进行重新渲染,并将状态设置为null,然后在数据可用时将其设置为正确的值。我希望这能向您解释情况,如果您有疑问,请让我知道问题不是因为多个未兑现的承诺@jdaz。我已经更新了演示,在加载时,两个按钮都将被禁用。因此,没有多个未兑现的承诺。但你可以看到这个问题仍然存在。