简体   繁体   English

设置状态时React上下文api返回未定义

[英]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.我最近开始学习反应,我正在使用上下文 api 来存储我的全局状态。

Here in MyProvider.js file i define my provider and its simply stores 2 arrays of json objMyProvider.js文件中,我定义了我的提供者,它只存储了 2 个 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,我通过这样做将我的App.js中的所有组件包装在 Provider 中,一边不使用 ReachRouter 来处理路由,

<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.在我的Home.js文件中,我在 useEffect 钩子中进行了一个网络调用,它成功地返回了我期望的 json,并使用该 json 响应更新上下文的状态,以便它可以全局可见。

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为了消除任何歧义,我的上下文是在一个名为MyContext.js的单独文件中创建的,我像这样创建了上下文

export const MyContext = React.createContext()

Why is the state.featuredVendors not updating when I set it?为什么state.featuredVendors在我设置时没有更新?

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.我注意到的另一个奇怪的事情是,如果我重新排列调用的顺序,即先调用getFeaturedListing,然后调用getFeaturedVendors,那么我的状态只更新featuresVendors和 featuresListings 将是一个空数组。

When you call useState the initialValue is only set once.当您调用useState ,initialValue 仅设置一次。 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.当您的 MyProvider 首次安装时,状态将使用您的setFeaturedListingssetFeaturedVendors方法进行初始化,但只要state值发生变化,这些方法就不会更新。 Therefore the value of state when you spread the values will always be its initial value.因此,当您传播值时state的值将始终是其初始值。

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: setState也可以使用始终接收当前值作为参数的函数调用,因此您可以重写这些方法来传播该值,如下所示:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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