我有一个createContext
组件,它使用useState
来设置从fetch
函数返回的多个值。但是在下面的代码中,当一个状态被更新时,其他状态将返回到原始值。
例如,在getCountryCode()
中,状态已更新为countryCode
,但随后iconCode
中的weatherInit()
获取其值,而countryCode
返回到原始的{{ 1}}。
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
而引起的,但是可以合并这些值还是有另一种方法来实现这一结果,我只需要以{{ 1}}到提供者上下文?
答案 0 :(得分:1)
这是因为调用state
时使用的是旧值setState()
。如here所述(向下滚动到“ 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};
});