Search code examples
reactjsreact-hooksreact-router-domuse-effect

BrowserRouter Link overriding onClick event


I'm attempting to update a State Hook after a click event. However, the BrowserRouter's Link around my component instance is overriding its onClick function.

But when I remove the 'Link To', the state successfully updates and prints in the console.

Eventually, I want to be able to pass the updated state to the PlayerPage component. But I'm using the console to test its updates for now - which it doesn't.

Here is my code:

Home.js - Contains click event.

import { Link } from "react-router-dom";
import { useState, useEffect } from "react";

export default function Home() {
  
const [task, setTask] = useState();

  useEffect(() => {
    console.log(task);
  },[task])

  return (
    <>
     <Header />
      <main className="home-main">
       <div className="main-wrap">
        <section className="card-container">
         <h1>Good Morning</h1>
           <h1>Choose Your Work Style</h1>

            <div className="card-wrap">
              <Link to="/PlayerPage">
                  <Card onClick={() => {setTask('Short Task')}}
                    taskName="Short Task"
                    description="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
                  />
              </Link>
            </div>
   </>
 );
}

PlayerPage.js - The destination of Link

import Header from "../components/Header";
import Timer from "../components/Timer";
import "./PlayerPage.scss";

export default function PlayerPage() {
  return (
    <>
      <Header />
      <main className="player-page-main">
        <div className="player-page-main-wrap">
          <div className="timer-title-wrap">
            <Timer />
            <h2 className="task-title">{Task Name Will Go Here}</h2>
          </div>
        </div>
      </main>
    </>
  );
}

Solution

  • Ok, this is what I was thinking was the case.

    The click event is propagating to the Link component, so you could call event.stopPropagation() to keep the click event from bubbling, but now the link won't work.

    If you use both then the link doesn't wait for the state to update.

    I think the best option is to not use any local state and pass the data in route state in the link. Use the object version of the to prop to specify the pathname and route state for the navigation transition.

    export default function Home() {
      return (
        <>
          ...
          <Link
            to={{
              pathname: "/PlayerPage",
              state: {
                task: 'Short Task',
              },
            }}
          >
            <Card
              taskName="Short Task"
              description="Lorem ipsum dolor sit amet, consectetur adipiscing elit."
            />
          </Link>
          ...
        </>
      );
    }
    

    Then access the route state from the location object in the receiving component.

    import { useLocation } from 'react-router-dom';
    
    export default function PlayerPage() {
      const { state } = useLocation();
      return (
        <>
          <Header />
          ...
            <h2 className="task-title">{state.task}</h2>
          ...
        </>
      );
    }