Reputation: 935
The version of react-router-dom is v6 and I'm having trouble with passing values to another component using Navigate.
I want to pass selected rows to another page called Report. But, I'm not sure I'm using the right syntax for navigate
method and I don't know how to get that state in the Report component.
Material-ui Table: I'm trying to use redirectToReport(rowData)
in onClick
parameter.
function TableRows(props){
return (
<MaterialTable
title="Leads"
columns={[
...
]}
data = {props.leads}
options={{
selection: true,
filtering: true,
sorting: true
}}
actions = {[{
position: "toolbarOnSelect",
tooltip: 'Generate a report based on selected leads.',
icon: 'addchart',
onClick: (event, rowData) => {
console.log("Row Data: " , rowData)
props.redirect(rowData)
}
}]}
/>
)}
LeadTable component
export default function LeadTable(props) {
let navigate = useNavigate();
const [leads, setLeads] = useState([]);
const [loading, setLoading] = useState(true);
async function fetchUrl(url) {
const response = await fetch(url);
const json = await response.json();
setLeads(json[0]);
setLoading(false);
}
useEffect(() => {
fetchUrl("http://localhost:5000/api/leads");
}, []);
function redirectToReport(rowData) {
navigate('/app/report', { state: rowData }); // ??? I'm not sure if this is the right way
}
return(
<div>
<TableRows leads={leads} redirect={redirectToReport}></TableRows>
</div>
)}
Report component
export default function ReportPage(state) {
return (
<div>
{ console.log(state) // This doesn't show anything. How to use the state that were passed from Table component here?}
<div className = "Top3">
<h3>Top 3 Leads</h3>
<ReportTop3 leads={[]} />
</div>
</div>
);}
Upvotes: 93
Views: 220483
Reputation: 131
In the latest version react-router-dom@6, you can redirect to another page using the useNavigate()
hook.
The useNavigate()
hook returns a function that lets you navigate to other pages with some states programmatically, for example:
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
...
navigate('/', {state: id});
Basically, this navigate function takes two parameters. The first one is declaring a path "/"
to tell where to navigate and the second one is optional where you can pass some states within curly braces (like {state: id}
) if you want.
Access Data:
Use the useLocation()
hook to access the state or data present to the child component.
First, you import a useLocation()
hook, which component you access the data or state. This hook returns the current location object.
import { useLocation } from "react-router-dom";
const { state } = useLocation();
// OR
const location = useLocation();
Then, easily we get the state or data in the location object, like that - location.state
.
To explore more, simply can check their doc -
https://reactrouter.com/en/main/hooks/use-navigate
https://reactrouter.com/en/main/hooks/use-location
Upvotes: 2
Reputation: 161
I stumbled on this post and I'm doing everything suggested above but for some reason I STILL couldn't get it to work. In the useLocation on the component I'm routing to I was getting null
for location?.state
I'm using MUI DataGrid, and in the onRowClick I was doing this
onRowClick={(rowData) => {
if (rowData) navigate('/some/page', { state: { data: rowData } })
}
I kept console logging rowData, and saw there was an object in there!! And it was still null. I was very confused. I realized I didn't need EVERYTHING coming from the rowData object, so I did this:
onRowClick={(rowData) => {
if (rowData) navigate('/some/page', { state: { data: rowData.row } })
}
Updating the data to pass with rowData.row
instead of the whole grid data fixed it. Which in hindsight, I should probably rename the rowData for onRowClick, since I thought it was just passing the row data initially.
Just posting this incase anyone else using MUI and trying to pass the row through the router came across this issue, and after following all the suggestions was still seeing null.
Upvotes: 2
Reputation: 51
on SABAOON BEDAR answer,
from component A: navigate('/', {state:"whatever"}
in component B: console.log(location.state) //output = whatever
Upvotes: 0
Reputation: 76
if you want to send data with usenavigate in functional component you can use like that
navigate(`/take-quiz/${id}`, { state: { quiz } });
and you can get it with uselocation hook like this
const location = useLocation();
location.state.quiz
there is your data
But you cannot get this data in props it;s tricky part ;)!!
Upvotes: 1
Reputation: 202846
Your navigate('/app/report', { state: rowData });
looks correct to me.
If you need state, use
navigate('success', { state })
.
interface NavigateFunction { ( to: To, options?: { replace?: boolean; state?: any } ): void; (delta: number): void; }
Your ReportPage
needs to be rendered under the same Router
that the component doing the push is under.
Route props are no longer passed to rendered components, as they are now passed as JSX literals. To access route state it must be done so via the useLocation
hook.
function ReportPage(props) {
const { state } = useLocation();
console.log(state);
return (
<div>
<div className="Top3">
<h3>Top 3 Leads</h3>
<ReportTop3 leads={[]} />
</div>
</div>
);
}
If the component isn't able to use React hooks then you still access the route state via a custom withRouter
Higher Order Component. Here's an example simple withRouter
HOC to pass the location
as a prop.
import { useLocation, /* other hooks */ } from 'react-router-dom';
const withRouter = WrappedComponent => props => {
const location = useLocation();
// other hooks
return (
<WrappedComponent
{...props}
{...{ location, /* other hooks */ }}
/>
);
};
Then access via props as was done in pre-RRDv6.
class ReportPage extends Component {
...
render() {
console.log(this.props.location.state);
return (
<div>
<div className="Top3">
<h3>Top 3 Leads</h3>
<ReportTop3 leads={[]} />
</div>
</div>
);
}
}
Upvotes: 91
Reputation: 29
2 things (just a suggestion): Rather than a ternary use &&
{location && <div>{location.state.name}</div>}
Why are you checking location and rendering location.state.name? I would use the check on the data you are fetching or make sure the data returns null or your value.
Upvotes: 2
Reputation: 139
On Sabaoon Bedar's Answer, you can check if there is any data or not before showing it :
Instead of this <div>{location.state.name}</div>
Do this { location != null ? <div>{location.state.name}</div> : ""}
Upvotes: 1
Reputation: 3689
version 6 react-router-dom
I know the question got answered but I feel this might be helpful example for those who want to use functional components and they are in search of passing data between components using react-router-dom v6.
Let's suppose we have two functional components, first component A, second component B. The component A wants to share data to component B.
usage of hooks: (useLocation,useNavigate)
import {Link, useNavigate} from 'react-router-dom';
function ComponentA(props) {
const navigate = useNavigate();
const toComponentB=()=>{
navigate('/componentB',{state:{id:1,name:'sabaoon'}});
}
return (
<>
<div> <a onClick={()=>{toComponentB()}}>Component B<a/></div>
</>
);
}
export default ComponentA;
Now we will get the data in Component B.
import {useLocation} from 'react-router-dom';
function ComponentB() {
const location = useLocation();
return (
<>
<div>{location.state.name}</div>
</>
)
}
export default ComponentB;
Note: you can use HOC if you are using class components as hooks won't work in class components.
Upvotes: 162