Search code examples
javascriptreactjsreact-routerreact-router-dom

How to navigate to different components in react.js


I want to make reusable buttons Left arrow and Right arrow, on clicking them I can navigate to different components/pages. I am making a calendar, I want to achieve, on pressing these arrow buttons I can navigate to different months. I can do this using <Link to="/path"> Link tag on every component, but this will be violation of Don't Repeat Yourself principle. Is there any way to achieve this functionality by making reusable button, where I don't have to pass <Link to="/path"> in every component?

These are routes on App.jsx

<Routes>
  <Route exact path='/' element={<HomePage />} />
  <Route exact path='/home' element={<HomePage />} />
  <Route path='nov2023' element={<SinglePage title='November 2023' />} />
  <Route path='dec2023' element={<SinglePage title='December 2023' />} />
  <Route path='jan' element={<SinglePage title='January 2024' />} />
  <Route path='feb' element={<SinglePage title='Febuary 2024' />} />
  <Route path='mar' element={<SinglePage title='March 2024' />} />
  <Route path='apr' element={<SinglePage title='April 2024' />} />
  <Route path='may' element={<SinglePage title='May 2024' />} />
  <Route path='jun' element={<SinglePage title='June 2024' />} />
  <Route path='jul' element={<SinglePage title='July 2024' />} />
  <Route path='aug' element={<SinglePage title='August 2024' />} />
  <Route path='sep' element={<SinglePage title='September 2024' />} />
  <Route path='oct' element={<SinglePage title='October 2024' />} />
  <Route path='nov' element={<SinglePage title='November 2024' />} />
  <Route path='dec' element={<SinglePage title='December 2024' />} />
  <Route path='*' element={<NotFoundPage />} />
</Routes>
import { useNavigate, useNavigation } from "react-router-dom";

const SinglePage = ({ title }) => {
  const navigation = useNavigate();
  return (
    <div className='h-screen px-2 bg-cyan-200'>
      <div className='flex flex-col items-center pt-20 space-y-5 text-center space-between'>
        <Logo />
        <MonthTitle title={title} />
        <SootheSensesPara />
      </div>
      <div className='flex justify-end space-x-2 items-center sm:px-[50px] md:px-[100px]'>
        <p onClick={() => navigation(-1)} className='flex-0'>
          **LA**
        </p>
        <div className='flex-1'>
          <BirdCard />
        </div>
        <p onClick={() => navigation(+1)} className='flex-0'>
          **RA**
        </p>
      </div>
    </div>
  );
};

export default SinglePage;
const HomePage = () => {
  return (
    <div className='bg-green-100 px-10 sm:px-[50px] md:px-[100px]'>
      <div className='pt-20 space-y-5 text-center '>
        <LogoSafex />
        <SootheSensesPara />
      </div>
      <div className='flex flex-col items-center justify-center space-y-5 '>
        <CalenderCard month='November' path='/nov2023' />
        <CalenderCard month='December' path='/dec2023' />
        <CalenderCard month='January' path='/jan' />
        <CalenderCard month='Febuary' path='/feb' />
        <CalenderCard month='March' path='/mar' />
        <CalenderCard month='April' path='/apr' />
        <CalenderCard month='May' path='/may' />
        <CalenderCard month='June' path='/jun' />
        <CalenderCard month='July' path='/jul' />
        <CalenderCard month='August' path='/aug' />
        <CalenderCard month='September' path='/sep' />
        <CalenderCard month='October' path='/oct' />
        <CalenderCard month='November' path='/nov' />
        <CalenderCard month='December' path='/dec' />
      </div>
    </div>
  );
};

export default HomePage;

On clicking LA and RA I want to navigate to previous and next component/page, i.e. on click RA from November 2023 to December 2023


Solution

  • My suggestion would be to load up all the month data into an array that can be searched.

    const months = [
      {
        id: "nov2023",
        month: "November",
        path: "/nov2023",
        title: "November 2023"
      },
      {
        id: "dec2023",
        month: "December",
        path: "/dec2023",
        title: "December 2023"
      },
      ....
      {
        id: "nov",
        month: "November",
        path: "/nov",
        title: "November 2024"
      },
      {
        id: "dec",
        month: "December",
        path: "/dec",
        title: "December 2024"
      }
    ];
    

    This array will be used to map to CalendarCard components in the HomePage and as a lookup utility function to compute the current, and next and previous month data.

    const HomePage = () => {
      return (
        <div className="bg-green-100 px-10 sm:px-[50px] md:px-[100px]">
          <div className="pt-20 space-y-5 text-center ">
            <LogoSafex />
            <SootheSensesPara />
          </div>
          <div className="flex flex-col items-center justify-center space-y-5 ">
            {months.map((month) => (
              <CalenderCard month={month} key={month.id} />
            ))}
          </div>
        </div>
      );
    };
    
    const getMonthData = (current) => {
      const index = months.findIndex((month) => month.id === current);
    
      return {
        current: months[index],
        previous: months[index - 1],
        next: months[index + 1]
      };
    };
    

    The SinglePage component will read a new month route path parameter and compute the current, next, and previous

    const SinglePage = () => {
      const navigation = useNavigate();
      const { month } = useParams();
    
      const { current, next, previous } = getMonthData(month);
    
      return (
        <div className="h-screen px-2 bg-cyan-200">
          <div className="flex flex-col items-center pt-20 space-y-5 text-center space-between">
            <Logo />
            <MonthTitle title={current?.title} />
            <SootheSensesPara />
          </div>
          <div className="flex justify-end space-x-2 items-center sm:px-[50px] md:px-[100px]">
            <button
              type="button"
              onClick={() => navigation(previous?.path)}
              className="flex-0"
            >
              {"<<"}
            </button>
            <div className="flex-1">
              <BirdCard />
            </div>
            <button
              type="button"
              onClick={() => navigation(next?.path)}
              className="flex-0"
            >
              {">>"}
            </button>
          </div>
        </div>
      );
    };
    
    <Routes>
      <Route path="/" element={<Navigate to="/home" replace />} />
      <Route path="/home" element={<HomePage />} />
      <Route path="/:month" element={<SinglePage />} />
      <Route path="*" element={<NotFoundPage />} />
    </Routes>
    

    Demo

    Edit how-to-navigate-to-different-components-in-react-js