I am using react-router-dom V6, with several different Class components that are connected with various nested within each component. In App.js, I have defined my browser router and routes as follows:
// import omitted for simplicity
function App() {
return (
<BrowserRouter>
<NAVBAR />
<Routes>
<Route path="/" element={ <SHOW_OPTIONS />} />
<Route path="/view_list/:list_id" element={ <SHOW_LIST />} />
<Route path="/authorize" element={ <AUTHORIZE_ITEM /> } />
</Routes>
</BrowserRouter>
);
}
export default App;
Inside of SHOW_OPTIONS, I have a option that brings you to /view_list/:list_id. Inside SHOW_OPTIONS, I need to take the list_id out of the parameter and then query a database for everything with that list_id, then display the list for the end user to browse.
Where I am running into issues is getting that query parameter out of the URL in my class component, since I cannot use any hooks directly from the class.
Here is what my SHOW_LIST class looks like:
export class SHOW_LIST extends Component {
constructor(props) {
super(props);
// Here I want to be able to assign my query
// param to this.state.list_id
this.state = {
list_id: '',
items: '',
items_selected: ''
}
}
componentDidMount() {
getListData(this.state.list_id) // this is == '' right now should be
.then(res => res.json()) // what was passed
.then(data => {
console.log(data);
this.setState({items: data});
})
.catch(err => {
console.log(err);
});
}
buildList() {
// where the list is actually
// built using this.state.items
return (
<div>I made it through!</div>
)
}
render () {
if(this.state.items != null) {
return (
{this.buildList()}
);
} else {
return (
<div id="loading">
Loading...
</div>
);
}
}
}
My link to the SHOW_LIST component looks like this:
<Link to = {{pathname: '/view_list/'+list_id}}></Link>
My initial solution was to do something like what's being done here, but since I need to access the query parameters within my class component, I'm not certain this resolution will work. How to pass params into link using React router v6?
Once you've followed the directions of the linked answer and created a custom withRouter HOC to inject the route path params you access them via the props object.
Given withRouter HOC:
const withRouter = WrappedComponent => props => {
const params = useParams(); // <-- these are the path params
// etc... other react-router-dom v6 hooks
return (
<WrappedComponent
{...props}
params={params}
// etc...
/>
);
};
And route path:
path="/view_list/:list_id"
Decorate the component and access them via this.props.params.list_id. Don't store list_id prop in state as this is actually an anti-pattern in React (storing passed props in local state).
export class SHOW_LIST extends Component {
constructor(props) {
super(props);
this.state = {
items: null,
items_selected: ''
}
}
componentDidMount() {
getListData(this.props.params.list_id) // <-- consume from props
.then(res => res.json())
.then(data => {
console.log(data);
this.setState({items: data});
})
.catch(console.error);
}
buildList() {
// where the list is actually
// built using this.state.items
return (
<div>I made it through!</div>
)
}
render () {
if (this.state.items !== null) {
return this.buildList();
} else {
return (
<div id="loading">
Loading...
</div>
);
}
}
}
Export the decorated SHOW_LIST:
export default withRouter(SHOW_LIST);