TypeError: Object is not iterable when working with react context

Viewed 5642

Im new to react and im trying to make a little project and ran into react context because i find it annoying passing down the props. I'm running into a problem with the useContext() hook.

My Context file

export function BoardProvider(props){

const [ board, setBoard ] = useState({
    id: null,
    name:  null,
    longterm: false,
    code: null,
    teacher: null,
    periodStart: null,
    periodEnd: null,
    totalDuration: null,
    phases: [],
    students: []

})
return (
    <BoardContext.Provider value={[board, setBoard]}>
        {props.children}
    </BoardContext.Provider>
)

}

And I'm trying to save the object from the context into this one like so:

const [ board, setBoard ]  = useContext(BoardContext);

I'm importing the Context like this:

import { BoardProvider } from '../../contexts/BoardContext'

The error says the object is not iterable so I assume that i declare somewhere that board is an array? If that is so where exactly and how can I fix the error?

Thanks for everyone helping in advance:)

3 Answers

Iterable Objects and regular objects in javascript are two different concepts.

According to the MDN web doc, Regular objects in javascript are a collection of properties and a property is an association between a name (or key) and a value. Value can be a function or any literal value.

Iterable objects are any object that contains the [Symbol.iterator] function. I'll give you an example of an Iterable object.

let iterableObject = {
    0: 'a',
    1: 'b',
    2: 'c',
    length: 3,
    [Symbol.iterator]: Array.prototype[Symbol.iterator]
};
for (var item of iterableObject) {
    console.log(item); 
}

To make object iterable we need to use [Symbol.iterator] but it will only work with array-like objects. Array-likes are objects that have indexes and length, so they look like arrays.

Tip: Arrays are built-in Iterable object

Now coming to your concern, you are using the array (or tuple) for destructuring the regular object literal. That's the reason you are getting the error as 'object is not iterable'. You need to have an iterable object for that when you are using an array (or tuple).

You can solve this problem in two ways. First, you can convert your object to an iterable object or the best solution that I will recommend is that you can use the object to destructure the regular object.

So, your code will look like this.

export function BoardProvider(props){

let defaultValue = {
  boards : [{
    id: null,
    name:  null,
    longterm: false,
    code: null,
    teacher: null,
    periodStart: null,
    periodEnd: null,
    totalDuration: null,
    phases: [],
    students: []
  }]
}
const [ board, setBoard ]= useState(defaultValue)

return (
    <BoardContext.Provider value={{board, setBoard}}>
        {props.children}
    </BoardContext.Provider>
)

Default Value would be JSON object in order to add data to it.

Use your context like this.

const { board, setBoard }  = useContext(BoardContext);

I got behind some tutorials again and found my mistake. I had my .Provider tag in the wrong file. It's supposed to be in the App where the Router is, where you call all the components so they all have access to the context.

function RouterApp() {

    const [ board, setBoard ] = useState(null);

    const value = useMemo(() => ({ board, setBoard}), [ board, setBoard])

    return (
        <Router>
            <div className="App">
                <BoardContext.Provider value={value}>
                    <Switch>
                        <Route path="/" exact component={BoardName} />
                        <Route path="/createboard/:name" exact component={TimePeriod} />
                        <Route path="/createboard:name/phases" exact component={PhaseForm} />
                    </Switch>
                </BoardContext.Provider>

            </div>
        </Router>
    );
}

export default RouterApp;

Here's my router function, where im passing the context to the components to BoardName, TimePeriod and PhaseForm.

Thanks for everyone helping me.

This error can be caused passing in the value to the provider incorrectly. Check the braces and brackets are correct:

Incorrect:

<RegulatorContext.Provider value={{state, setState}}>
    <Regulator />
</RegulatorContext.Provider>

Correct:

<RegulatorContext.Provider value={[state, setState]}>
    <Regulator />
</RegulatorContext.Provider>
Related