简体   繁体   中英

React context api returning undefined when setting the state

I've recently started learning react and i'm using the context api to store my global state.

Here in MyProvider.js file i define my provider and its simply stores 2 arrays of json obj

import {MyContext} from "./MyContext";
import React, {useState} from "react";

export const MyProvider = (props) => {
    const intialState = {
        featuredListings: [],
        setFeaturedListings: (val) => setState({...state, featuredListings: val}),
        featuredVendors: [],
        setFeaturedVendors: (val) => setState({...state, featuredVendors: val})
    }

    const [state, setState] = useState(intialState)

    return (
        <MyContext.Provider
            value={state}
        >
            {props.children}
        </MyContext.Provider>
    );
}

I'm wrapping all my components in my App.js in the Provider by doing this , side not using ReachRouter to handle routing,

<MyProvider>
    <div className="content">
        <Header/>
        <Router>
            <Home path="/"/>
        </Router>
    </div>
    <Footer />
</MyProvider>

In my Home.js file I make a network call in the useEffect hook which successfully returns the json which i expect and with that json response i update the state of the context so that it can be visible globally.

My code for that is

export const Home = () => {
    let state = useContext(MyContext)

    async function apiCalls() {
        const featuredVendors = await getFeaturedVendors()
        console.log("featuredVendors - ", featuredVendors) // the correct response is returned
        state.setFeaturedVendors(featuredVendors)

        const featuredListings = await getFeaturedListing()
        console.log("featuredListings - ", featuredListings) // the correct response is returned
        state.setFeaturedListings(featuredListings)
    }

    useEffect(() => {
        apiCalls()
    }, []);

    return (
        <div>
            {console.log(state.featuredVendors)}  // empty array
            {console.log(state.featuredListings)} // contains correct values
        </div>
    )
}

]

To remove any ambiguity my Context is created in a separate file which is Called MyContext.js and I create the Context like so

export const MyContext = React.createContext()

Why is the state.featuredVendors not updating when I set it?

Also another strange thing i noticed is if I rearrange the orders of the calls , ie call the getFeaturedListing first followed by the getFeaturedVendors then my state only updates for featuredVendors and featuredListings will be an empty array.

When you call useState the initialValue is only set once. When your MyProvider is first mounted, the state is initialised with your setFeaturedListings and setFeaturedVendors methods but these are not updated whenever the value of state changes. Therefore the value of state when you spread the values will always be its initial value.

setState can also be called with a function that always receives the current value as an argument, so you could rewrite these methods to spread that value like so:

    const intialState = {
        featuredListings: [],
        setFeaturedListings: (val) => setState(state => ({...state, featuredListings: val})),
        featuredVendors: [],
        setFeaturedVendors: (val) => setState(state => ({...state, featuredVendors: val}))
    }

Or, alternatively, you could move these functions outside of your state altogether.

export const MyProvider = (props) => {
  const intialState = {
      featuredListings: [],
      featuredVendors: [],
  }
  const [state, setState] = useState(intialState)
  return (
      <MyContext.Provider
          value={{
            ...state,
            setFeaturedListings: (val) => setState({...state, featuredListings: val}),
            setFeaturedVendors: (val) => setState({...state, featuredVendors: val})
          }}
      >
          {props.children}
      </MyContext.Provider>
  );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM