reactjsmaterial-uireact-routerreact-router-dom

react-router-dom v6 useNavigate passing value to another component


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>
);}

Solution

  • Your navigate('/app/report', { state: rowData }); looks correct to me.

    react-router-v6

    If you need state, use navigate('success', { state }).

    navigate

    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>
        );
      }
    }