I have an app code
import React from "react";
import { Route, Switch } from "react-router-dom";
import Minidrawer from './components/Drawer/Minidrawer'
import { makeStyles } from '@mui/styles';
import Box from '@mui/material/Box';
import Main from "./components/Main/Main";
import {useSelector} from 'react-redux'
const useStyles = makeStyles({
container: {
display: "flex"
}
});
export default function App() {
const classes = useStyles();
const user = useSelector((state) => state.auth);
return (
<Box sx={{ display: 'flex' }}>
<Minidrawer currUser={user}/>
<Switch>
<Route exact from="/" render={props => <Main childText="home" currUser={user} {...props} />} />
<Route exact path="/auth" render={props => <Main childText="auth" currUser={user} {...props} />} />
<Route exact path="/register-client" render={props => <Main childText="registerClient" currUser={user} {...props} />} />
</Switch>
</Box>
);
}
I have to pass currUser to all child components imported in App but I do not want to duplicate the code, what are different ways to achieve this so that all of the components have access to currUser?
CodePudding user response:
if I understand what you want to do, you want to pass props to all children of a component, if the components are simple components you can do as follows:
import React from "react";
import Main from "./Main";
import PassPropsToNormalComponents from "./PassPropsToNormalComponents";
export default function App() {
const user = {
username: "lakhdar"
};
return (
<div style={{ display: "flex" }}>
<PassPropsToNormalComponents currUser={user}>
<Main childText="home" />
<Main childText="auth" />
<Main childText="registerClient" />
</PassPropsToNormalComponents>
</div>
);
and this is the PassPropsToNormalComponents file
import React from "react";
export default function PassPropsToNormalComponents({ children, ...props }) {
const childrenWithProps = React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
return React.cloneElement(child, { ...child.props, ...props });
}
return child;
});
return <>{childrenWithProps}</>;
}
but in your case passing the props to the routes wont' make the routes pass the props to their rendered components so we need an extra step here:
first the file where we provide the props to the parent:
import React from "react";
import { Route, Switch } from "react-router-dom";
import Main from "./Main";
import PassPropsToRouteComponents from "./PassPropsToRouteComponents";
export default function App() {
const user = {
username: "lakhdar"
};
return (
<div style={{ display: "flex" }}>
<Switch>
<PassPropsToRouteComponents currUser={user}>
<Route
exact
from="/"
render={(props) => {
return <Main childText="home" {...props} />;
}}
/>
<Route
exact
path="/auth"
render={(props) => <Main childText="auth" {...props} />}
/>
<Route
exact
path="/register-client"
render={(props) => <Main childText="registerClient" {...props} />}
/>
</PassPropsToRouteComponents>
</Switch>
</div>
);
}
and finally, the extra step is to get the rendered element and pass it its own props the props from the parent, and the file looks like this:
import React from "react";
export default function PassPropsToRouteComponents({ children, ...props }) {
const childrenWithProps = React.Children.map(children, (child) => {
if (React.isValidElement(child)) {
const routerChild = child.props.render();
return React.cloneElement(child, {
...child.props,
render: () => {
return React.cloneElement(routerChild, {
...routerChild.props,
...props
});
}
});
}
return child;
});
return <>{childrenWithProps}</>;
}
link to working codesandbox: https://codesandbox.io/s/gracious-meadow-dj53s
I hope this is what you've been looking for.
CodePudding user response:
You could use redux or the context API.
Redux: https://react-redux.js.org/
Context API: https://reactjs.org/docs/context.html