我有一个createContext
组件,它使用useState
来设置从fetch
函数返回的多个值。但是,在下面的代码中,当一个状态更新时,其他状态将返回到原始值。
例如,在getCountryCode()
中,状态会针对countryCode
进行更新,但随后iconCode
weatherInit()
获取其值并countryCode
返回到原始US
。
import React, { createContext, useState, useEffect } from 'react';
export const GlobalConsumer = createContext();
export const GlobalProvider = ({ children }) => {
const [state, setState] = useState({
menuPanel: false,
countryCode: 'US',
weatherLoading: true,
iconCode: '',
fahrenheit: '',
celcius: '',
showCelcius: false
});
const getCountryCode = () => {
const url = `https://ipapi.co/json/`;
fetch(url)
.then(data => data.json())
.then(data => {
const countryCode = data.country;
setState({ ...state, countryCode });
});
};
const weatherInit = () => {
const CITY_LAT = '...';
const CITY_LON = '...';
const OW_KEY = '...';
const url = `//api.openweathermap.org/data/2.5/weather?lat=${CITY_LAT}&lon=${CITY_LON}&units=imperial&appid=${OW_KEY}`;
fetch(url)
.then(data => data.json())
.then(data => {
const iconCode = data.weather[0].id;
setState({ ...state, iconCode });
const fahrenheit = Math.round(data.main.temp_max);
setState({ ...state, fahrenheit });
const celcius = Math.round((5.0 / 9.0) * (fahrenheit - 32.0));
setState({ ...state, celcius });
setTimeout(() => {
setState({ ...state, weatherLoading: false });
}, 150);
});
};
useEffect(() => {
getCountryCode();
weatherInit();
}, []);
return (
<GlobalConsumer.Provider
value={{
contextData: state,
togglemMenuPanel: () => {
setState({ ...state, menuPanel: !state.menuPanel });
},
toggleCelcius: () => {
setState({ ...state, showCelcius: !state.showCelcius });
}
}}
>
{children}
</GlobalConsumer.Provider>
);
};
我相信这是因为每个value
都需要自己的useState
。但是,是否可以合并这些值,或者是否有其他方法可以实现此结果,其中我只需要作为data
传递给提供程序上下文?
这是因为您在调用setState()
时使用的是旧的state
值。如此处所述(向下滚动到"Note"块(,您必须将函数传递给setState
调用:
const iconCode = data.weather[0].id;
setState(prevState => ({ ...prevState, iconCode }));
const fahrenheit = Math.round(data.main.temp_max);
setState(prevState => ({ ...prevState, fahrenheit }));
const celcius = Math.round((5.0 / 9.0) * (fahrenheit - 32.0));
setState(prevState => ({ ...prevState, celcius }));
setTimeout(() => {
setState(prevState => ({ ...prevState, weatherLoading: false }));
}, 150);
与类组件中的 setState 方法不同,useState 不会自动合并更新对象。您可以通过将函数更新程序表单与对象传播语法相结合来复制此行为:
setState(prevState => {
// Object.assign would also work
return {...prevState, ...updatedValues};
});