0

I have created the following context in React:

import { useBoolean } from "@chakra-ui/react"
import { createContext, FC } from "react"

type useBooleanReturn = ReturnType<typeof useBoolean>

export const MobileContext = createContext<
  [show: useBooleanReturn[0], setShow: useBooleanReturn[1]] | undefined
>(undefined)

// --- PROVIDER
const MobileProvider: FC = ({ children }) => {
  const [show, setShow] = useBoolean()

  return (
    <MobileContext.Provider value={[show, setShow]}>
      {children}
    </MobileContext.Provider>
  )
}

export default MobileProvider

So far so good, but when I try and use this context it turns out that what is being passed down is undefined. That is, in the following code value is undefined:

const value = React.useContext(MobileContext)

I don't know why that is, though, since I use the useBoolean hook when setting up the context -- i.e., this line: const [show, setShow] = useBoolean(). I then pass on show and setShow to my context with this line: value={[show, setShow]}. As such, shouldn't value be defined with an array with two values (namely show and setShow)?

Any idea why that is NOT happening and what can I do to fix it?

Thanks.

UPDATE Here is the full example of when I call useContext:

import * as React from "react"
import MobileProvider, { MobileContext } from "./context.mobile"

const Mobile = () => {
  const value = React.useContext(MobileContext)

  console.log("value:", value)
  ...

The above is what I did for testing purposes. Here is what I the code is actually supposed to look like:

import * as React from "react"
import Base from "./base"

import Header from "./Header"
import Menu from "./Menu"
import Footer from "./Footer"


import MobileProvider, { MobileContext } from "./context.mobile"

const Mobile = () => {
  const [show, setShow] = React.useContext(MobileContext)

  return (
    <MobileProvider>
      <Base onClick={setShow.toggle} ref={ref} show={show}>
        <Header onClick={setShow.toggle} />
        <Menu />
        <Footer />
      </Base>
    </MobileProvider>
  )
}

export default Mobile
Moshe
  • 6,011
  • 16
  • 60
  • 112
  • 1
    Please show FULL EXAMPLE, where you actually call `useContext`, can you reproduce it in a codesandbox? – Dennis Vash Jun 29 '21 at 16:40
  • @DennisVash I have updated the question. Please let me know if you need anything else. – Moshe Jun 29 '21 at 16:46
  • Still not a full example, how do you render `Mobile`? Please show the `MobileProvider` component tree – Dennis Vash Jun 29 '21 at 16:49
  • @DennisVash The Provider was supposed to be there (I had done an experiment where I moved the Provider higher up, but it didn't help). Either way, I have re-edited the code with `MobileProvider` included. – Moshe Jun 29 '21 at 16:58
  • 1
    But your `Mobile` component is clearly __above__ `MobileProvider` (it includes it). So it gets _default_ context value, not the actual provided by the provider. – aleksxor Jun 29 '21 at 17:00

1 Answers1

3

You suppose to call useContext on PROVIDER'S CONSUMERS.

In other words, the component which calls the useContext (Mobile) must be a child of MobileProvider.

In your case, its not a consumer, thats not how the API defined, therefore you will get the default value (undefined) since its called out of context.

const Mobile = () => {
  // NOT A CONSUMER
  const [show, setShow] = React.useContext(MobileContext)

  return (
    <MobileProvider>
      ...
    </MobileProvider>
  )
}

Move the component to MobileProvider tree

<MobileProvider>
  <Mobile/>
</MobileProvider>

const Mobile = () => {
  // NOW A CONSUMER
  const [show, setShow] = React.useContext(MobileContext)

  return (
    <Base onClick={setShow.toggle} ref={ref} show={show}>
        ...
    </Base>
  )
}
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118