Reputation: 141
I'm having trouble ensuring a parent's property values persist across route changes between nested routes. I've created a short working example to demonstrate.
In the below React app, I have a Classes component which renders cards containing information about different classes. I've set up an onClick event that triggers when the user clicks a card, redirecting the user to the ClassInfo component which contains information about the class they clicked on- either information about enrolled students, or groups. The user can toggle between information on enrolled students or groups by clicking links to redirect to the appropriate route. My problem is that, when you try to toggle between the ClassGroups and ClassStudents components by clicking the relevant links, the props with the classId I pass down to identify the class the user selected is reset to undefined and I can no longer access them.
import ReactDOM from "https://cdn.skypack.dev/[email protected]";
import React, {useEffect, useState, Fragment} from "https://cdn.skypack.dev/[email protected]";
import {Redirect, Link, BrowserRouter, Route, Switch} from "https://cdn.skypack.dev/[email protected]"
function ClassStudents(props){
const [studentInfo] = React.useState([{classId: 1,studentId: 1 ,name: "Sam"},{classId: 2, studentId: 2, name: "Tom"} ,{classId: 3, studentId: 3, name: "Maria"},{classId: 1, studentId: 4, name: "Tina"}])
return(
<div>
<h1>Students Component</h1>
{studentInfo.map((info) => (
info.classId===props.location.state.classId? <div>{info.name}</div>: null
))}
</div>
)
}
function ClassGroups(props){
const [groupInfo] = React.useState([{classId: 1,groupId: 1 ,name: "Falcons"},{classId: 1, groupId: 2, name: "Rockets"}, ,{classId: 2, groupId: 3, name: "Rockets"}])
return(
<div>
<h1>Groups Component</h1>
{groupInfo.map((info) => (
info.classId===props.location.state.classId? <div>{info.name}</div>: null
))}
</div>
)
}
function ClassInfo(props){
return(
<div>
<h1>{props.location.state.className} Class Info Component</h1>
<Link to ="/classinfo/students">
Students
</Link>
<Link to="/classinfo/groups">
Groups
</Link>
<Switch>
<Route path="/classinfo/students" render={(props) => <ClassStudents {...props}/>}/>
<Route path="/classinfo/groups" render={(props) => <ClassGroups {...props}/>}/>
</Switch>
</div>
)
}
function Classes(props){
const [classInfo] = React.useState([{classId: 1, className: "History"},{classId: 2, className: "Math"}, {classId: 3, className: "English"}])
const [redirect, setRedirect] = React.useState(null)
const [classId, setClassId] = React.useState(null)
const [className, setClassName] = React.useState(null)
function handleClick(classId,className){
setRedirect("/classinfo/students")
setClassId(classId)
setClassName(className)
}
return(
redirect ?
(<Redirect to={{pathname: redirect, state: {classId: classId, className: className}}}/>)
:
(
classInfo.map((info, index)=>(
<div key={index} onClick={() => handleClick(info.classId, info.className)} className="classCard">
<div>{info.classId}</div>
<div>{info.className}</div>
</div>
))
)
)
}
ReactDOM.render(
<React.StrictMode>
<BrowserRouter>
<Switch>
<Route path="/classinfo" render={(props) => <ClassInfo {...props} />}/>
<Route path="/" component={Classes}/>
</Switch>
</BrowserRouter>
</React.StrictMode>
,document.getElementById('root'))
Upvotes: 1
Views: 97
Reputation: 11037
You had things mostly working. You just needed to make sure the state is propagated through the links. Unfortunately, the way history api works, the state is reset with every page change (history.push/replace).
You can set the state from a Link using the object form of the to
prop: https://reactrouter.com/web/api/Link/to-object
<Link to={{pathname: "/classinfo/students", state: props.location.state}}>
Students
</Link>
<Link to={{pathname: "/classinfo/groups", state: props.location.state}}>
Groups
</Link>
https://codepen.io/ZachHaber/pen/oNWaZVY?editors=1111
Upvotes: 1