我想知道什么是初始化状态并保持与服务器同步的最佳方式模式。在过去的几天里,我阅读并尝试了很多,但没有发现任何解决我问题的方法。
这个例子真的很简单。有一个状态--为了简单起见,在这个例子中它是一个数字,尽管在现实生活中它应该是一个对象--我需要从服务器上检索。一旦检索到,我希望它能与服务器同步。getValueFromServer是一个mock,在setTimeout中随机等待一段时间后返回一个随机值。
所以,为了初始化我的状态,我在一个空数组上使用一个useEffect作为依赖,为了保持同步,我使用一个带有状态的useEffect作为依赖。
问题是它试图保存一个未定义的值。日志如下。
1 -> 第一次初始化。
2 -> API调用保存在服务器中的值:未定义。
3 -> API调用保存在服务器中的数值:6.026930847574949。
我得到了什么。
1:按预期安装运行。
2:这个我没有想到。我猜它是因为 "useState "而被触发的。
3:一旦我们得到服务器的响应就会运行。有点明显,但是很麻烦,因为我到底为什么要保存这个。
最好的方法是什么?在useEffect中使用类似 "isInitialized "的标志与依赖关系,感觉有点黑,不专业。
下面的代码,你也可以在这里找到工作。https:/codesandbox.iosoptimistic-rgb-uce9f
import React, { useState, useEffect } from "react";
import { getValueFromServer } from "./api";
export default function App() {
const [value, setValue] = useState();
useEffect(() => {
async function initialize() {
console.log("Initializing for first time");
let serverValue = await getValueFromServer();
setValue(serverValue);
}
initialize();
}, []);
useEffect(() => {
console.log("API call to save in server value: ", value);
}, [value]);
const handleClick = () => {
setValue(value + 1);
};
return (
<div className="App">
<h1>Value: {value}</h1>
<button onClick={handleClick}>Add 1 to value</button>
</div>
);
}
这里最好的方法是什么?在useEffect中使用类似 "isInitialized "的标志与依赖,感觉有点黑,不专业。
你可以使用一个标志,或者用默认值初始化对象在 useState
const { Fragment, useState, useEffect } = React;
const getValueFromServer = () => new Promise((resolve, reject) => setTimeout(() => resolve(Math.random())), 1000)
const App = () => {
const [value, setValue] = useState(null);
const [isLoading, setLoading] = useState(true);
useEffect(() => {
let isUnmounted = false;
getValueFromServer().then(serverValue => {
console.log("Initializing for first time");
if(isUnmounted) {
return;
}
setValue(serverValue);
setLoading(false);
})
return () => {
isUnmounted = true;
}
}, []);
useEffect(() => {
if(!value) {
return () => {}
}
console.log("API call to save in server value: ", value);
setTimeout(() => setLoading(false), 50);
}, [value]);
const handleClick = () => {
setLoading(true);
setValue(value + 1);
};
return <div className="App">
{isLoading ? <Fragment>
<span>Loading...</span>
</Fragment> : <Fragment>
<h1>Value: {value}</h1>
<button onClick={handleClick}>Add 1 to value</button>
</Fragment>}
</div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
<script src="https://unpkg.com/react/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom/umd/react-dom.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-polyfill/7.10.1/polyfill.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>
<div id="root"></div>
您的应用程序在忙碌的同时还在做其他事情 await
在你的第一场比赛中,你会发生一些事情。useEffect
钩子函数。 在这里,"其他东西 "是 "执行你的第二个 useEffect
钩子功能"。 serverValue
钩子函数",因此 value
,此时还没有定义,所以你的 console.log
印花 undefined
一旦你的 await
诺言解析为一个值和 setValue
召之即来,挥之即去 useEffect
钩子函数的依赖关系发生变化,导致你的函数第二次运行(并打印出你期望的值)。
如果你必须有两个 useEffect
钩,然后就在第二种情况下保释出来。value
未定义。
useEffect(() => {
if (value === undefined) {
return;
}
console.log('value is:', value);
}, [ value ]);