Reputation: 131
I have a context and try to pass it to my children components:
const PatientContext = createContext([{}]);
function App() {
const [selectedPatient, setSelectedPatient] = useState([]);
const [patients, setPatients] = useState([{ name: 'Taras', age: 19 }, { name: 'Taras', age: 19 }, { name: 'Taras', age: 19 }]);
async function patientsHasChanged() {
const patientService = new PatientService();
const loadedPatients = await patientService.getPatients();
setPatients(loadedPatients);
};
return (
<div className='app'>
<PatientContext.Provider value={[selectedPatient, setSelectedPatient, patients, patientsHasChanged]}>
<Sidebar />
<Content />
</PatientContext.Provider>
</div>
);
}
But if I try use it in my child components I am always getting empty object, how i can fix it? img with my problem here
UPD: Here's my component with using context:
const Sidebar = (props) => {
const [patients, selectedPatient, setSelectedPatient] = useContext(PatientContext);
return (
<div className='sidebar'>
<div className='search'>
<input type="text" placeholder='Search' />
<a href="/TechTask/new"><button>New patient</button></a>
</div>
<div className='list'>
<ul>
{patients.map((p) =>
<li onClick={setSelectedPatient}>
<div className='name'>
{p.name}
</div>
<div className='age'>
{p.age}
</div>
</li>)
}
</ul>
</div>
</div>
);
};
Upvotes: 0
Views: 215
Reputation: 168913
Your problem is you're using an array ([]
) for the context; arrays have a given order. You pass in [selectedPatient, setSelectedPatient, patients, patientsHasChanged]
, and you're unpacking things in a different order ([patients, selectedPatient, setSelectedPatient]
), so you get the "wrong" objects.
Instead, use an object ({}
) so you can unpack it as you like, and remember to memoize the context value to avoid unnecessary rerenders.
const PatientContext = React.createContext(null);
const Sidebar = (props) => {
const { patients, selectedPatient, setSelectedPatient } = React.useContext(PatientContext);
return (
<div className="sidebar">
<div className="search">
<input type="text" placeholder="Search" />
<a href="/TechTask/new">
<button>New patient</button>
</a>
</div>
<div className="list">
<ul>
{patients.map((p) => (
<li onClick={setSelectedPatient}>
<div className="name">{p.name}</div>
<div className="age">{p.age}</div>
</li>
))}
</ul>
</div>
</div>
);
};
function App() {
const [selectedPatient, setSelectedPatient] = React.useState([]);
const [patients, setPatients] = React.useState([
{ name: "Taras", age: 19 },
{ name: "Taras", age: 19 },
{ name: "Taras", age: 19 },
]);
function patientsHasChanged() {/* elided since SO doesn't support async */}
const patientContext = React.useMemo(() => ({ selectedPatient, setSelectedPatient, patients, patientsHasChanged }), [
selectedPatient,
setSelectedPatient,
patients,
patientsHasChanged,
]);
return (
<div className="app">
<PatientContext.Provider value={patientContext}>
<Sidebar />
</PatientContext.Provider>
</div>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="root"></div>
Upvotes: 2