React钩子useState在上下文提供者中设置多个状态

时间:2019-09-17 20:56:34

标签: javascript reactjs react-hooks

我有一个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}}到提供者上下文?

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};
});