React 无法更新状态
React cannot update state
我不明白为什么我不能更新我的状态(参见 setCoords)。包含 200 代码的请求 returns 和我要检索的元素已存在:
这是我的代码:
const App = () => {
const [city, setCity] = useState("");
const [forecast, setForecast] = useState(null);
const [coords, setCoords] = useState({});
const handleSearchChange = ev => {
setCity(ev.target.value);
};
async function onSearch() {
if (city) {
await apiGet(`/geo/1.0/direct?q=${city}`)
.then(r => r.json())
.then(r => setCoords({lat: r[0].lat, lon:r[0].lon})); // doesn't't set anything
await console.log(coords) // console logs {}
await apiGet(
`/data/2.5/onecall?lat=${coords.lat}&lon=${coords.lon}&exclude=current,minutely,hourly,alerts`
)
.then(r => r.json())
.then(r => setForecast(r));
}
}
感谢您的帮助!
尝试使用回调
...
const onSearch = useCallback(async () {
if (city) {
await apiGet(`/geo/1.0/direct?q=${city}`)
.then(r => r.json())
.then(r => setCoords({lat: r[0].lat, lon:r[0].lon})); // doesn't't set anything
await console.log(coords) // console logs {}
await apiGet(
`/data/2.5/onecall?lat=${coords.lat}&lon=${coords.lon}&exclude=current,minutely,hourly,alerts`
)
.then(r => r.json())
.then(r => setForecast(r));
}
}, [coords]);
...
参考:https://reactjs.org/docs/hooks-reference.html#usecallback
需要注意的一件事是不要将 await
与 then
混用(更多信息:Can await and then be mixed in one implementation?)。由于您使用的是 async
,我建议您全部更改为 await
,如下所示
另一件需要注意的事情是 setStates
调用(即 setCoords
和 setForecast
和 setCity
)本质上是 异步的 ,这意味着设置状态后立即 console.log
将 而不是 记录刚刚更新的值。相反,React 会将这些 setState 安排到下一个渲染中 - 因此,您只能 see/access 在下一个渲染周期中更新的值。如果你想记录值,你可以把它们放在 HTML 的 <pre>
标签内,或者在开头做 console.log
,如下所示:
const App = () => {
const [city, setCity] = useState("");
const [forecast, setForecast] = useState(null);
const [coords, setCoords] = useState({});
console.log("City", city, "Forecast", forecast, "Coords", coords);
const handleSearchChange = ev => {
setCity(ev.target.value);
};
async function onSearch() {
if (city) {
const resNonJson = await apiGet(`/geo/1.0/direct?q=${city}`)
const resJson = await resNonJson.json())
const item = resJson[0];
setCoords({lat: item.lat, lon: item.lon}));
// Note that `setState` is async so console.log will not get the just-updated value
console.log(coords) // {}
console.log(item) // {lat:..., lon:...}
const resNonJson2 = await apiGet(
`/data/2.5/onecall?lat=${item.lat}&lon=${item.lon}&exclude=current,minutely,hourly,alerts`
)
const resJson2 = await resNonJson2.json())
setForecast(resJson2);
}
}
... (other codes that I trust you do correctly)
return <div>
<pre>{JSON.stringify(coords)}</pre>
</div>
setState() 操作在 React 中是异步的。这一切意味着您不能依赖在 setState 中应用的新状态值立即应用。
与 setState 一起,fetch() 在 nature.Hence 中也是异步的,console.log 语句不会等待 setState() 或 fetch() 被执行。在这种情况下,您始终可以通过 setState() 的回调参数来处理它。
await apiGet(`/geo/1.0/direct?q=${city}`)
.then(r => r.json())
.then(r => setCoords(data => {lat: r[0].lat, lon:r[0].lon}))
我不明白为什么我不能更新我的状态(参见 setCoords)。包含 200 代码的请求 returns 和我要检索的元素已存在:
这是我的代码:
const App = () => {
const [city, setCity] = useState("");
const [forecast, setForecast] = useState(null);
const [coords, setCoords] = useState({});
const handleSearchChange = ev => {
setCity(ev.target.value);
};
async function onSearch() {
if (city) {
await apiGet(`/geo/1.0/direct?q=${city}`)
.then(r => r.json())
.then(r => setCoords({lat: r[0].lat, lon:r[0].lon})); // doesn't't set anything
await console.log(coords) // console logs {}
await apiGet(
`/data/2.5/onecall?lat=${coords.lat}&lon=${coords.lon}&exclude=current,minutely,hourly,alerts`
)
.then(r => r.json())
.then(r => setForecast(r));
}
}
感谢您的帮助!
尝试使用回调
...
const onSearch = useCallback(async () {
if (city) {
await apiGet(`/geo/1.0/direct?q=${city}`)
.then(r => r.json())
.then(r => setCoords({lat: r[0].lat, lon:r[0].lon})); // doesn't't set anything
await console.log(coords) // console logs {}
await apiGet(
`/data/2.5/onecall?lat=${coords.lat}&lon=${coords.lon}&exclude=current,minutely,hourly,alerts`
)
.then(r => r.json())
.then(r => setForecast(r));
}
}, [coords]);
...
参考:https://reactjs.org/docs/hooks-reference.html#usecallback
需要注意的一件事是不要将 await
与 then
混用(更多信息:Can await and then be mixed in one implementation?)。由于您使用的是 async
,我建议您全部更改为 await
,如下所示
另一件需要注意的事情是 setStates
调用(即 setCoords
和 setForecast
和 setCity
)本质上是 异步的 ,这意味着设置状态后立即 console.log
将 而不是 记录刚刚更新的值。相反,React 会将这些 setState 安排到下一个渲染中 - 因此,您只能 see/access 在下一个渲染周期中更新的值。如果你想记录值,你可以把它们放在 HTML 的 <pre>
标签内,或者在开头做 console.log
,如下所示:
const App = () => {
const [city, setCity] = useState("");
const [forecast, setForecast] = useState(null);
const [coords, setCoords] = useState({});
console.log("City", city, "Forecast", forecast, "Coords", coords);
const handleSearchChange = ev => {
setCity(ev.target.value);
};
async function onSearch() {
if (city) {
const resNonJson = await apiGet(`/geo/1.0/direct?q=${city}`)
const resJson = await resNonJson.json())
const item = resJson[0];
setCoords({lat: item.lat, lon: item.lon}));
// Note that `setState` is async so console.log will not get the just-updated value
console.log(coords) // {}
console.log(item) // {lat:..., lon:...}
const resNonJson2 = await apiGet(
`/data/2.5/onecall?lat=${item.lat}&lon=${item.lon}&exclude=current,minutely,hourly,alerts`
)
const resJson2 = await resNonJson2.json())
setForecast(resJson2);
}
}
... (other codes that I trust you do correctly)
return <div>
<pre>{JSON.stringify(coords)}</pre>
</div>
setState() 操作在 React 中是异步的。这一切意味着您不能依赖在 setState 中应用的新状态值立即应用。 与 setState 一起,fetch() 在 nature.Hence 中也是异步的,console.log 语句不会等待 setState() 或 fetch() 被执行。在这种情况下,您始终可以通过 setState() 的回调参数来处理它。
await apiGet(`/geo/1.0/direct?q=${city}`)
.then(r => r.json())
.then(r => setCoords(data => {lat: r[0].lat, lon:r[0].lon}))