2

I have defined a context using createContext that wraps some of my components like

import MyContext from './mycontext.js'
import A from 'a.js';
import B from b.js';
<MyContext>
    <A/>
    <B/>
</MyContext>

where A is defined something like

import C from './c.js'
const A = () => {
    return (<C/>);
}

And C is define something like

import MyContext from 'mycontext.js';

const C = () => {
    const { value, setValue } = useContext(MyContext);
    return (<div>`This is the value - ${!!value ? value : 'UNK'}`</div>)
}

Finally the context is created like

const MyContext = createContext({value: '', setValue: () => {}});

The problem is that I get a runtime error

TypeError: Object is not iterable (cannot read property Symbol(Symbol.iterator))

From the component C.

I want to make provision for calling C outside of the provider. Not as a wrapped child of the provider. Where does this error come from and how do I work around it?

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Kevin
  • 91
  • 1
  • 1
  • 7

1 Answers1

0

From only what I can tell from the code snippets it appears you're not rendering any context provider and not providing a context value.

Instead of trying to use the MyContext context as a React component, render the Provider component.

<MyContext.Provider value={{ value: 42, setValue: console.log }}>
  <A />
  <B />
</MyContext.Provider>

Edit usecontext-with-no-context

enter image description here

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
  • In the original question I have the line const MyContext = createContext({value: '', setValue: () => {}}); – Kevin Jan 12 '22 at 17:02
  • @Kevin Yes, I saw that and that was also copy/pasted into the codesandbox link in my answer. This is the default value. The `defaultValue` argument is **only** used when a component does not have a matching Provider above it in the tree. https://reactjs.org/docs/context.html#reactcreatecontext You still need to render a Provider component ***and*** provide a context value. – Drew Reese Jan 12 '22 at 17:09
  • What if I wand to use for example component 'C' not as a child of the provider (in other orders just )? Component 'C' still calls useContext. It seems the return values in that case are undefined? – Kevin Jan 13 '22 at 13:03
  • @Kevin Are you asking about rendering component `C` *outside* of a provider's subtree? Yes, `C` will still use, or try to, the context, but in this case it will use the `defaultValue` you passed to `createContext`, i.e. `{ value: '', setValue: () => {} }` from `createContext({value: '', setValue: () => {}});`. – Drew Reese Jan 13 '22 at 16:15
  • It doesn't seem to use the default value. I sets it to undefined. – Kevin Jan 13 '22 at 22:06
  • @Kevin *What* is setting *what* to undefined? Can you be more precise? Just render a context consumer within the ReactTree created by a context provider and you should be able to access the context value (*so long as you are actually providing a **value***). – Drew Reese Jan 13 '22 at 22:19
  • The return from useContext is undefined when the component is not a child of the provider. – Kevin Jan 14 '22 at 02:03
  • @Kevin I see the defined `defaultValue` returned from the context when used outside the provider. See this codesandbox [fork](https://codesandbox.io/s/usecontext-with-no-context-forked-9hvgw?file=/src/App.js). If the context value was truly undefined then attempting to destructure from it would throw an exception. That being said, why are you so concerned with what a context returns when used improperly? – Drew Reese Jan 14 '22 at 02:45