How can I render a component in React to 2 different components? - javascript

I'm working on a ReactJS project. I have 3 components in the main page "Index component" as follows,
Nav-
Featured-
Footer
My Nav component has 2 links to 2 different components.
My Switch is as follows,
<Switch>
<Route path="/home" component={props => <Index {...props} />} />
<Route path="/register" component={Register} />
<Route path="/login" component={Login} />
<Route path="/cart" component={Cart} />
<Redirect from="/" to="home" />
</Switch>
I also have my Index component as follows,
<React.Fragment>
<Search />
<Nav history={history} />
{this.homePageComponents()}
<Route
path="/home/bedding"
component={props => (
<Bedding beddingProducts={this.beddingProducts()} {...props} />
)}
/>
<Route
path="/home/bath"
component={props => (
<Bath bathProducts={this.bathProducts()} {...props} />
)}
/>
<Route path="/home/search" component={Search} />
</React.Fragment>
I'm trying to render the Nav component to both Bath and Bedding products but whenever I import it and use it there it gives me an Error saying this.props.history.replace is undefined.
This is the project's link.
https://github.com/MaxOffline/beetle

I think you can solve your issue with using "withRouter" wrapper component which react-router provide to wrap your Nav component.
https://reacttraining.com/react-router/web/api/withRouter

If you console.log(this.props) in the render method of nav.jsx you'll see that it contains a history object but that there is no replace method on that object.
You may be looking for the this.props.history.push method?

I found a very simple way to fix the problem.
All I needed to do is render components to the homepage conditionally so I simply added the following helper method to my "Index" Component.
homePageComponents = () => {
const featuredProducts = this.state.products.filter(
product => product.featured === true
);
if (this.props.history.location.pathname === "/home") {
return <Featured featuredProducts={featuredProducts} />;
}
};

Related

A route is not covered in layout component, but still renders layout in React

I'm having to trouble making a route without layout component. Please check my code first.
// App.js
const App = () => {
return (
<div className={styles.container}>
<Header />
<main>
<QuizBoxContainer>
<Routes>
<Route path='/' element={<QuizSelect />} />
<Route path='quiz-for/:language' element={<QuizCard />} />
<Route path='result' element={<ResultPage />} />
</Routes>
</QuizBoxContainer>
<Routes>
<Route path='wrong-answer' element={<WrongAnswer />} />
</Routes>
</main>
</div>
)
}
In the code, <QuizBoxContainer> is the layout component.
What I was trying to do is making another path,
<Routes>
<Route path='wrong-answer' element={<WrongAnswer />} />
</Routes>
outside of <QuizBoxContainer> so I can use another layout on this component.
However, when I go to WrongAnswer,
It still renders.
What is wrong with my code, and how can I solve it?
Issue
The is because the QuizBoxContainer layout wrapper component is not rendered on any route, it's always rendered.
Solution
Move QuizBoxContainer into a layout route. You'll need to update QuizBoxContainer so it renders an Outlet component instead of the children prop.
Example:
import { Outlet } from 'react-router-dom';
const QuizBoxContainer = () => {
...
return (
... quiz container layout/styling ...
<Outlet /> // <-- nested routes render content here
...
);
};
Render QuizBoxContainer on a layout route wrapping the routes you want to render within it, render the wrong answer route outside the layout route.
const App = () => {
return (
<div className={styles.container}>
<Header />
<main>
<Routes>
<Route element={<QuizBoxContainer />}>
<Route path='/' element={<QuizSelect />} />
<Route path='quiz-for/:language' element={<QuizCard />} />
<Route path='result' element={<ResultPage />} />
</Route>
<Route path='wrong-answer' element={<WrongAnswer />} />
</Routes>
</main>
</div>
)
}

React Router v6 not working with URL Slugs

I'm trying to make react-router-dom work with a simple url: /user/{name} but for some reason cannot get it to load the page with the url slug for the name.
This is the return of my App function component:
<>
<MainNavBar navigation={navigation} />
<Routes>
<Route index={true} element={<Home />} exact />
<Route path="user" element={<User />} exact>
<Route
path=":name"
render={
({ match: { params: { name } } }) => {
console.log(name);
console.log("test2");
return (<UserPage
userName={name}
/>);
}}
/>
</Route>
<Route path="*" element={<PageNotFound />} />
</Routes>
</>
This is the User component; a placeholder for my debugging atm.
const User = () => (
<div>
<header className="App-header">
<Outlet />
</header>
</div>
);
When I go to http://localhost:3000/user/test it loads the User component but not the children (the Outlet/UserPage elements)
I've tried lots of combinations but seem to be doing something wrong, so any help would be very appreciated. Thanks!
In react-router-dom v6 the Route components no longer have render or component props, they render their components on the element prop. Use the useParams hook to access the route match params. If UserPage is a component that can't use React hooks, then use a wrapper function component to access the route match param and pass it as a prop.
const UserPageWrapper = () => {
const { name } = useParams();
useEffect(() => {
console.log({ name }); // <-- log param in effect
}, [name]);
return <UserPage userName={name} />;
};
...
<>
<MainNavBar navigation={navigation} />
<Routes>
<Route index element={<Home />} />
<Route path="user" element={<User />}>
<Route path=":name" element={<UserPageWrapper />} />
</Route>
<Route path="*" element={<PageNotFound />} />
</Routes>
</>

Invalid Hook Call useSelector() with react-router

I have my state in Redux working for a shopping cart. Let's say I have two pages and want to pass the state from the shopping page to the cart/checkout page.
I am calling useSelector from this page but I get an error about an invalid Hook Call.
const CartPage = () => {
const selectedProducts = useSelector(
(state) => (state && state.products) || []
);
return (
<PageContainer>
This is the Cart Page
</PageContainer>);
};
export default CartPage;
And this component is rendered by react-dom-router like this
<AppContainer>
<Navigation />
<Switch>
<Route exact path="/" render={WelcomePage} />
<Route path="/cart" render={CartPage} />
<Route path="/shopping" render={ShoppingPage} />
</Switch>
</AppContainer>
I am storing the state from a component inside the page component ShoppingPage.
The useSelector hook is working only inside components outside the react-router-dom. Is there a way to get the state in one of these components?
EDIT: Somehow it worked using a callback inside the render attribute of Route
Here the fixed code
<AppContainer>
<Navigation />
<Switch>
<Route exact path="/" render={() => <WelcomePage /> } />
<Route path="/cart" render={() => <CartPage /> } />
<Route path="/shopping" render={() => <ShoppingPage /> } />
</Switch>
</AppContainer>

How to prioritize the route in React?

I'm making React app, and I have some Routers.
const App = () => {
return (
<div>
<Header/>
<div>
<Route path="/LogIn" render={() => <LogIn />} />
<Route path="/Shop" render={() => <GoodsContainer />} />
<Route path="/Delivery" render ={() => <Delivery />} />
</div>
<Footer />
</div>
)
}
When I open my page for the first time, there're only Headercomponent and Footer component, and It's logically because the url has not contain pathes which I have set to the Routes.
So, my question is how to show always , for example the Route <Route path="/Shop" render={() => <GoodsContainer />} /> when the user open the site.
Redirect isn't my solution.
path prop could either be a string or an array of strings. You can define multiple paths for GoodsContainer component using an array of strings as a value for path prop
<Route path={["/", "/Shop"]} render={() => <GoodsContainer />} />
and don't forget to either use exact prop on Route component or wrap all Route component with Switch component otherwise / path will match all other routes.
You can check #Yousef answer for this , Also if you arent passing any props, then do this instead. Don't forget to give the exact
<Route path={["/", "/Shop"]} exact render={GoodsContainer} />
But if you are passing then do this
<Route path={["/", "/Shop"]} exact render={(props)=> <GoodsContainer {...props} />} />

Is there a best practice way to hide component using react router?

To hide the navbar on the home component I am doing the following
const NavbarComponent = (props) => {
console.log(props);
if (props.match.path === '/') {
return null;
} else
return (
it works fine, I need to have access to the router so I can send people to locations dependant on the props object , is there a better way to do it such that I have all router logic in the same place?
this is the current state of my router
return (
<div>
<Router>
<Route component={Navbar} />
<Switch>
<Route exact path="/" component={Home} />
<Route exact path="/api/:city/electronics" component={Electronics} />
<Route exact path="/api/:city/labour" component={Labour} />
<Route exact path="/api/posts/item/:id" component={ItemDetails} />
<Route exact path="/create/:city/:category" component={CreatePost} />
</Switch>
</Router>
</div>
);
thanks for your time.
I'm not sure I understand why your NavBar component is in it's own Route. Any components contained within the Router have access to the entire Router api, including Link - they do not need to be a Route to do so.
I would suggest wrapping all the Routes that include the NavBar with that component. The Routes will then be displayed as children of the Navbar component.
Here is a simplified example:
// App.js
return (
<div>
<Router>
<Switch>
<Route exact path="/" component={Home} />
<NavBar>
<Route exact path="/electronics" component={Electronics} />
<Route exact path="/labour" component={Labour} />
</NavBar>
</Switch>
</Router>
</div>
);
//NavBar.js
return (
<>
<div>
<Link to="/electronics">Electronics</Link>
<Link to="/labour">Labour</Link>
</div>
<div>{props.children}</div>
</>
);
codesandbox

Categories

Resources