I send a usestate through AppContexet.Provider
to AppContexet.Consumer
. I can see at the components - the data arrived - but when I try to map the state, I get an error. What am I doing wrong?
This is the parent:
import {useState} from 'react'
import Ex53Child from './Ex53Child'
import AppContexet from './Appcontext'
import React, {Component} from 'react';
const Ex53perent = ()=>
{
const [name,setName] = useState('')
const [age,setAge] = useState()
const [users,setUsers] = useState ([])
const [user,setUser] = useState ({name : '' , age : ''})
return(<AppContexet.Provider value = {{...users}}>
<div>
<h1> Ex53perent comp </h1>
Name: <input type = "text" onChange = {e=>setUser({...user ,name : e.target.value})}/><br/>
Age : <input type = "text" onChange = {e=>setUser({...user ,age : e.target.value})}/><br/>
<input type = "button" value ="Add" onClick ={e=>setUsers([...users,user])}/>
<Ex53Child/>
</div>
</AppContexet.Provider>
)
}
export default Ex53perent;
This is the child :
import {useState} from 'react'
import AppContexet from './Appcontext'
import Ex53GrenChild from './Ex53GrenChild'
const Ex53Child = ()=>
{
const [myUesr,setMyUser] = useState([])
return(<AppContexet.Consumer>
{
dataContext =>
(
<div>
<h1> Ex53Child comp </h1>
{
dataContext.users.map((item,index)=>
{
return<il key = {index}>
<li>{item.name}</li>
<li>{item.age}</li>
</il>
})
}
<Ex53GrenChild/>
</div>
)
}
</AppContexet.Consumer>
)
}
export default Ex53Child;
And this is the appcontext
file:
import React from 'react'
const AppContexet = React.createContext();
export default AppContexet;
A single value works just fine, but I can't map the array from some reason.
The users
state is an array:
const [users, setUsers] = useState([]);
And you are spreading the array into an object:
<AppContexet.Provider value={{ ...users }}>
...
</AppContexet.Provider>
This makes the context value an object where the array indices are now object keys and the array values are object values.
You could keep it this way, and then you'll need to convert the context value back to an array in the child:
<AppContexet.Consumer>
{dataContext => (
<div>
<h1>Ex53Child comp</h1>
{Object.values(dataContext).map((item, index) => {
return (
<il key={index}>
<li>{item.name}</li>
<li>{item.age}</li>
</il>
);
})
}
<Ex53GrenChild/>
</div>
)}
</AppContexet.Consumer>
It's better to just keep the users
and context values consistently an array. Don't spread the users
state into the context value.
<AppContexet.Provider value={{ users }}>
...
</AppContexet.Provider>
Now's the context value is an object with a single users
property that is the users
state.
<AppContexet.Consumer>
{dataContext => (
<div>
<h1>Ex53Child comp</h1>
{dataContext.users.map((item, index) => {
return (
<il key={index}>
<li>{item.name}</li>
<li>{item.age}</li>
</il>
);
})
}
<Ex53GrenChild/>
</div>
)}
</AppContexet.Consumer>
useContext
hookSince Ex53Child
is a function component it's a bit silly to use the AppContexet.Consumer
component render function. Use the useContext
hook instead.
const Ex53Child = () => {
const [myUesr, setMyUser] = useState([]);
const { users } = useContext(AppContexet);
return (
<div>
<h1>Ex53Child comp</h1>
{users.map((item, index) => (
<il key={index}>
<li>{item.name}</li>
<li>{item.age}</li>
</il>
))}
<Ex53GrenChild />
</div>
);
}
users
as a propAdditionally, since Ex53perent
is directly rendering Ex53Child
, using the context is unnecessary complexity when the users
state could just simply be passed as a prop.
const Ex53perent = () => {
const [name, setName] = useState('');
const [age, setAge] = useState();
const [users, setUsers] = useState([]);
const [user, setUser] = useState({ name: '', age: '' });
return (
<div>
<h1> Ex53perent comp </h1>
Name:{" "}
<input
type="text"
onChange={e => setUser({ ...user, name: e.target.value })}
/>
<br/>
Age:{" "}
<input
type="text"
onChange={e => setUser({ ...user, age: e.target.value })}
/>
<br/>
<input
type="button"
value="Add"
onClick={e => setUsers([...users, user])}
/>
<Ex53Child users={users} /> // <-- pass users as prop to child
</div>
);
};
...
const Ex53Child = ({ users }) => { // <-- access users from props
const [myUesr, setMyUser] = useState([]);
return (
<div>
<h1>Ex53Child comp</h1>
{users.map((item, index) => (
<il key={index}>
<li>{item.name}</li>
<li>{item.age}</li>
</il>
))}
<Ex53GrenChild />
</div>
);
}