Home > Blockchain >  How to pass props to Layout Routes in react-router-dom 6
How to pass props to Layout Routes in react-router-dom 6

Time:03-12

I couldn't find in official React Router Documentation how to pass props from nested routes to Layout route (page). Instead of <Routes> I am using useRoutes hook.

As you can see from provided code, I want to provide props (image id and title) from children routes (Login, InvestorRegister, ServiceProviderRegister, ForgotPassword, ResetPassword) to layout route wrapper page (LeftImageLayout).

How to do that? Any suggestions or code improvment will be appreciated. Thank you

I know that I can use ContextApi to pass props from parent to child, but I can't do that in my case.

Layout

import { Outlet } from "react-router-dom";
import { styled } from "@mui/material/styles";
import Typography from "@mui/material/Typography";
import Grid from "@mui/material/Grid";

const Wrapper = styled("div")({
  backgroundSize: "cover",
  backgroundRepeat: "no-repeat",
  minHeight: "100vh",
  display: "flex",
  flexDirection: "column",
  justifyContent: "space-between",
});

const LeftImageLayout = ({ image, text }) => {
  return (
    <Grid container spacing={0} justifyContent="center" alignItems="center">
      <Grid item xs={12} md={8}>
        <Wrapper
          sx={{
            background: `url("https://picsum.photos/1280/957?random=${image}")`,
          }}
        >
          <Typography
            variant="h1"
            sx={{ alignSelf: "flex-start", paddingLeft: 2, paddingTop: 2 }}
          >
            BuildUp
          </Typography>
          <Typography variant="h2" sx={{ alignSelf: "center" }}>
            {text}
          </Typography>
          <Typography variant="span" />
        </Wrapper>
      </Grid>
      <Grid item xs={12} md={4}>
        <Outlet />
      </Grid>
    </Grid>
  );
};

export default LeftImageLayout;

Routes

export default function Router() {
  return useRoutes([
    ...
    {
      element: <LeftImageLayout />,
      children: [
        {
          path: "/login",
          element: <Login text="Text for login page" image="4" />,
        },
        {
          path: "/investor-registration",
          element: <InvestorRegister text="Text for investor page" image="5" />,
        },
        {
          path: "/service-provider-registration",
          element: (
            <ServiceProviderRegister
              text="Text for service provider page"
              image="6"
            />
          ),
        },
        {
          path: "/forgot-password",
          element: (
            <ForgotPassword text="Text for forgot password page" image="6" />
          ),
        },
        {
          path: "/reset-password",
          element: (
            <ResetPassword text="Text for reset password page" image="7" />
          ),
        },
      ],
    },
    ...
  ]);
}

Login

const Login = () => {
  return ( // Place for React hook form );
};

export default Login;

CodePudding user response:

You could use useState hook. In Routes, you'd need to add this code:

const [image, setImage] = useState('')
const [text, setText] = useState('')

I'm not sure if you need to both set and display image and text in your children components. To make your life a little bit easier, you'd probably want to put that state into an object that you'd pass as a prop:

const params = {
  image,
  setImage,
  text,
  setText
}

This would be an example entry in your children array:

{
  path: "/login",
  element: <Login params={params} />,
}

In Login component, you'd add the following:

const Login = ({ params }) => {
  const { setImage, setText } = params
  
  useEffect(() => {
    setText('Text for login page')
    setImage('4')
  }, [])
  
  //...
}

LeftImageLayout would take params as a prop, as well, the diference being that you'd access text and image values when deconstructing params.

CodePudding user response:

I will use window.location.pathname to conditionally render content (image id and text), like this:

const LeftImageLayout = () => {
  const pathName = window.location.pathname.substring(1);

  let image = "";
  let text = "";

  switch (pathName) {
    case "login":
      text = "Hundreds of on-demand workers are open to work!";
      image = "1";
      break;
    case "investor-registration":
      text =
        "Access the selection of hundreds construction related on demand workers, ready to work with you.";
      image = "2";
      break;
    case "service-provider-registration":
      text =
        "Offer your services to a various investors looking for talented construction related people like you.";
      image = "3";
      break;
    case "forgot-password":
      text =
        "We help talents in construction related services connect with local investors.";
      image = "4";
      break;
    case "reset-password":
      text =
        "Talents and experienced investors combined to bring extraordinary results.";
      image = "5";
      break;
    default:
      break;
  }

  return (
    <Grid container spacing={0} justifyContent="center" alignItems="center">
      <Grid item xs={12} md={8}>
        <Wrapper
          sx={{
            background: `url("https://picsum.photos/1280/957?random=${image}")`,
          }}
        >
          <Typography
            variant="h1"
            sx={{ alignSelf: "flex-start", paddingLeft: 2, paddingTop: 2 }}
          >
            BuildUp
          </Typography>
          <Typography variant="h2" sx={{ alignSelf: "center" }}>
            {text}
          </Typography>
          <Typography variant="span" />
        </Wrapper>
      </Grid>
      <Grid item xs={12} md={4}>
        <Outlet context={{ image, text }} />
      </Grid>
    </Grid>
  );
};

Instead of window.location.pathname we can use hook useLocation()

  • Related