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

需要注意的一件事是不要将 awaitthen 混用(更多信息:Can await and then be mixed in one implementation?)。由于您使用的是 async,我建议您全部更改为 await,如下所示

另一件需要注意的事情是 setStates 调用(即 setCoordssetForecastsetCity)本质上是 异步的 ,这意味着设置状态后立即 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}))