Why React does not render component when I redirect to product page - javascript

I have an error and can not find any solution in google. The error appears when I want to go to a poduct page and press a button on home page to go to a product page and there I don't have any element rendered, I used React Route to user be able to go to product page and add it to a cart and suppose I did something wrong with providing path but not sure.
VM867:236 Matched leaf route at location "/2" does not have an element. This means it will render an <Outlet /> with a null value by default resulting in an "empty" page.
Here is a code for Item Element:
import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
function Item() {
const { id } = useParams();
const [item, setItem] = useState([]);
const [loading, setLoading] = useState(false);
console.log("item", item);
// Fetching Data
useEffect(() => {
const fetchedData = async () => {
setLoading(true);
const response = await fetch(`https://fakestoreapi.com/products/${id}`);
const data = response.json();
setItem(data);
};
fetchedData();
}, []);
return (
<div className="container">
{loading ? (
<>
<h3>Loading.....</h3>
</>
) : (
<div className="container">
<p>{item.title}</p>
</div>
)}
</div>
);
}
export default Item;
And for App.js
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import ItemsComponent from "./Componets/ItemsComponent";
import Navbar from "./Componets/Navbar";
import Home from "./Componets/Home";
import Item from "./Componets/Item";
import About from "./Componets/About";
import AboutLink from "./Componets/AboutLink";
import Contact from "./Componets/Contact";
import Footer from "./Componets/Footer";
import "./App.css";
function App() {
return (
<>
<Router>
<Navbar />
<Routes>
<Route
exact
path="/"
element={
<>
<Home />
<ItemsComponent />
</>
}
/>
<Route exact path="/:id" component={<Item />} />
<Route exact path="/about" element={<About />} />
</Routes>
<AboutLink />
<Footer />
</Router>
</>
);
}
export default App;
It also affected all styling.

Maybe it's because you have
<Route exact path="/:id" component={<Item />} />
instead of
<Route exact path="/:id" element={<Item />} />
?

I think that instead of this
<Route exact path="/:id" component={<Item />} />
you want either of those
<Route exact path="/:id" component={Item} />
<Route exact path="/:id" element={<Item />} />

Related

nested path dosent work in react router dom

I am trying to create a browser router for my app but the nested paths are not working.
import React from 'react';
import './App.css';
import HomeScreen from './screens/HomeScreen';
import {
createBrowserRouter,
createRoutesFromElements,
Route,
RouterProvider
} from 'react-router-dom';
import LoginScreen from './screens/LoginScreen';
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<HomeScreen />}>
<Route path="dashboard" element={<LoginScreen />} />
{/* ... etc. */}
</Route>
)
);
function App() {
return (
<div className="App">
<RouterProvider router={router} />
</div>
);
}
export default App;
On this code both "localhost:3000/" and "localhost:3000/dashboard" are opening the HomeScreen page only.
Can you tell me what I should do to make "/dashboard" open LoginSrceen instead of HomeScreen?
If you are nesting routes then the parent route necessarily needs to render an Outlet component for nested routes to render their element content into.
Example:
import { Outlet } from 'react-router-dom';
const HomeScreen = () => {
...
return (
... Home screen UI ...
<Outlet /> // <-- nested routes render content here
...
);
};
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<HomeScreen />}>
<Route path="dashboard" element={<LoginScreen />} />
{/* ... etc. */}
</Route>
)
);
function App() {
return (
<div className="App">
<RouterProvider router={router} />
</div>
);
}
On the off-hand chance that you actually want HomeScreen and LoginScreen to render each on their own discrete routes, then they should not be nested one in the other, but instead should be rendered as sibling routes. Render HomeScreen on an index route such that it will be rendered when the URL path matches the parent route, e.g. "/".
const router = createBrowserRouter(
createRoutesFromElements(
<Route path="/">
<Route index element={<HomeScreen />} />
<Route path="dashboard" element={<LoginScreen />} />
{/* ... etc. */}
</Route>
)
);
function App() {
return (
<div className="App">
<RouterProvider router={router} />
</div>
);
}

Parameters Routing

I'm having a problem in getting the output of the "match" object value in this parameter routing code.
This is class where I use match:
import React from "react";
const ProductDetails = (props) => {
console.log(props.match);
return <h1>Details No. </h1>;
};
export default ProductDetails;
And the code I use for using the route is:
import React, { Component } from "react";
import NavBar from "./navbar";
import ProductDetails from "./productDetails";
class App extends Component {
render() {
return (
<React.Fragment>
<NavBar
productsCount={this.state.Product.filter((p) => p.count > 0).length}
/>
<main className="container">
<Routes>
<Route path="/about" element={<About />} />
<Route path="/" element={<Home />} />
<Route path="/contact" element={<Contact />} />
<Route
path="/cart"
element={
<ShoppingCart
products={this.state.Product}
onReset={this.resetData}
onIncrement={this.incrementEntry}
onDelete={this.deleteEntery}
/>
}
/>
<Route path="/products/:id" element={<ProductDetails />} />
</Routes>
</main>
</React.Fragment>
);
}
}
And I get the answer as "undefined" and a lot of red errors msgs.
if you are using react router v6 and what you want to do is getting the id, it would be:
import React from "react";
const ProductDetails = () => {
const {id} = useParams();
return <h1>Details No. {id}</h1>;
};
export default ProductDetails;
or if you really want the match object:
import React from "react";
const ProductDetails = () => {
const match = useMatch();
return <h1>Details No.</h1>;
};
export default ProductDetails;
What is element? If you use react-router-dom for routing you must set the component for any route.
<BrowserRouter>
<Route path ="/about" component= {<About />} />
<Route path ="/" component= {<Home/>}/>
<Route path ="/contact" component= {<Contact/>}/>
<Route path ="/cart" component= {<ShoppingCart
products= {this.state.Product}
onReset ={this.resetData}
onIncrement ={this.incrementEntry}
onDelete = {this.deleteEntery}/>}/>
<Route path="/products/:id" component={<ProductDetails />}/>
</BrowserRouter>

react router use params returns empty object

I have a web app which is under development which is just like google drive using firebase. I have this useParams() in Dashboard Screen which is the main page of the App with All the different Folder Routes. So for this screen i have used useParams and now when i console.log(params) it shows an empty object {} and also when i click the button it does not navigate only the URL changes
Github Code :- https://github.com/KUSHAD/RDX-Drive/
In App.js
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import PrivateRoute from './Components/Route/PrivateRoute';
import Dashboard from './Screens/Main/Dashboard';
import ViewProfile from './Screens/Profile/ViewProfile';
import Signup from './Screens/Auth/Signup';
import Login from './Screens/Auth/Login';
import ForgotPassword from './Screens/Auth/ForgotPassword';
function App() {
return (
<>
<div className='App'>
<div className='main'>
<BrowserRouter>
<Switch>
{/* Drive */}
<PrivateRoute exact path='/' component={Dashboard} />
<PrivateRoute
exact
path='/folder/:folderId'
component={Dashboard}
/>
{/* Profile */}
<PrivateRoute path='/profile' component={ViewProfile} />
{/* Auth */}
<Route path='/signup' component={Signup} />
<Route path='/login' component={Login} />
<Route path='/forgot-password' component={ForgotPassword} />
</Switch>
</BrowserRouter>
</div>
</div>
</>
);
}
export default App;
In Dashboard.js
import NavBar from '../../Components/Shared/NavBar';
import Container from 'react-bootstrap/Container';
import AddFolderButton from '../../Components/Main/AddFolderButton';
import { useDrive } from '../../services/hooks/useDrive';
import Folder from '../../Components/Main/Folder';
import { useParams } from 'react-router-dom';
export default function Dashboard() {
const params = useParams();
console.log(params);
const { folder, childFolders } = useDrive();
return (
<div>
<NavBar />
<Container fluid>
<AddFolderButton currentFolder={folder} />
{childFolders.length > 0 && (
<div className='d-flex flex-wrap'>
{childFolders.map(childFolder => (
<div
key={childFolder.id}
className='p-2'
style={{ maxWidth: '250px' }}>
<Folder folder={childFolder} />
</div>
))}
</div>
)}
</Container>
</div>
);
}
Issue
After scouring your repo looking for the usual suspect causes for "it does not navigate only the URL changes" I didn't find anything odd like multiple Router components, etc. I think the issue is your PrivateRoute component isn't passing the props to the Route correctly. You're destructuring a prop called rest and then spread that into the Route, but you don't pass a rest prop to the PrivateRoute
export default function PrivateRoute({ component: Component, rest }) { // <-- rest prop
const { currentUser } = useAuth();
return (
<Route
{...rest} // <-- nothing is spread/passed here
render={props => {
return currentUser ? (
<Component {...props} />
) : (
<Redirect to='/login' />
);
}}
/>
);
}
The routes, these are not passed any prop named rest:
<PrivateRoute exact path='/' component={Dashboard} />
<PrivateRoute
exact
path='/folder/:folderId'
component={Dashboard}
/>
What I believe to be occurring here is the exact and path props aren't passed to the underlying Route component and so the first nested component of the Switch is matched and rendered, the "/" one that doesn't have any route params.
Solution
The fix is to spread the rest of the passed props into rest instead of destructuring a named rest prop.
export default function PrivateRoute({ component: Component, ...rest }) {
const { currentUser } = useAuth();
return (
<Route
{...rest}
render={props => {
return currentUser ? (
<Component {...props} />
) : (
<Redirect to='/login' />
);
}}
/>
);
}
An improvement of your private route may be as follows:
export default function PrivateRoute(props) {
const { currentUser } = useAuth();
return currentUser ? (
<Route {...props} />
) : (
<Redirect to='/login' />
);
}
This checks your user authentication and renders either a Route or Redirect. This pattern allows you to use all the regular Route props so you aren't locked into using the render prop to render the component.

How to setup Routes using React Router in my ReactJS app?

I have some problem with react-router. It doesn't go to Edit page when I click on id. The id is in URL, but it doesn't do anything.
const Main = (props) => {
const { pathname } = props.location;
return (
<Fragment>
<div>
<div className="container">
<Header />
{pathname === "/create" ? <Create /> : null}
{pathname === '/edit/:id' ? <Edit /> : null}
{pathname === "/" ? <Home /> : null}
</div>
</div>
</Fragment>
);
};
export default withRouter(Main);
app.js:
require('./components/Index');
import React from 'react'
import ReactDOM from "react-dom"
import Index from "./components/Index";
import { BrowserRouter as Router} from "react-router-dom";
import { ToastContainer } from 'react-toastify';
const App =() =>{
}
if (document.getElementById('app')) {
ReactDOM.render(<Router> <Index /> <ToastContainer /></Router>, document.getElementById('app'));
}
index.js:
import React from "react";
import { Route, Switch } from "react-router-dom";
import Main from "./CRUD/Main";
import Create from "./CRUD/Create";
import Edit from "./CRUD/Edit";
import Home from "./CRUD/Home";
const Index = (props) => {
return (
<Main>
<Switch>
<Route path="/Create" component={Create} />
<Route path='/edit/:id' component={Edit} />
<Route exact path="/" component={Home} />
</Switch>
</Main>
);
};
export default Index;
I think main.js have some problems with pathname.
You don't need to do conditional rendering like you are doing in Main when using react-router. Switch will automatically render the first child <Route> or <Redirect> that will match the location.
Hence, you need to remove Main from your router component i.e. Index so that it looks like as shown below:
const Index = (props) => {
return (
<>
<NavBar /> {/* NavBar is optional, I just added for example */}
<Switch>
<Route path="/create" component={Create} />
<Route path="/edit/:id" component={Edit} />
<Route exact path="/" component={Home} />
</Switch>
</>
);
}
NavBar: (Links; just for example)
function NavBar() {
return (
<ul>
<li>
<Link to="/create">Go to create</Link>
</li>
<li>
<Link to="/edit/123">Go to edit with id = 123</Link>
</li>
<li>
<Link to="/">Go to home</Link>
</li>
</ul>
);
}
Now, when you click on the above links, it will automatically take you to the related component (as declared in routes i.e. Index). (no manually condition checking)
And example, to retrieve the URL param i.e. id in Edit component using useParams hook:
function Edit() {
const { id } = useParams<{ id: string }>(); // Remove <{ id: string }> if not using TypeScript
return <h2>Edit, {id}</h2>;
}

React router rendering two child components instead of just one

I'm trying to add routes to my application but for some reason there are two components being rendered to the page instead of just one.
My code looks like this (the relevant part):
import React from "react";
import Board from "./Components/Board";
import Navbar from "./Components/Navbar";
import TaskDetail from "./Components/TaskDetail";
import { LanesProvider } from "./Context/lanes.context";
import { TasksProvider } from "./Context/tasks.context";
import { BrowserRouter, Route, Switch } from "react-router-dom";
function App(props) {
const getTask = props => {
return <TaskDetail />;
};
return (
<>
<LanesProvider>
<TasksProvider>
<Navbar />
<Board />
<BrowserRouter>
<Switch>
<Route exact path="/" render={() => <Board />} />
<Route exact path="/board" render={() => <Board />} />
<Route exact path="/board/:taskName" render={() => getTask()} />
</Switch>
</BrowserRouter>
</TasksProvider>
</LanesProvider>
</>
);
}
Now basically when I'm navigating to "localhost/board/test" I would expect to just see the <TaskDetail/> component but instead I get the <Board /> AND <TaskDetail/>.
I didn't expect this to happen because of the exact boolean.
FYI: getTask() is only returning a component right now because I wanted to get the routes to work first before implementing further logic.
So far I could not find a solution to this.
Thank you in advance.
There is a <Board /> component outside your <BrowserRouter>
import React from "react";
import Board from "./Components/Board";
import Navbar from "./Components/Navbar";
import TaskDetail from "./Components/TaskDetail";
import { LanesProvider } from "./Context/lanes.context";
import { TasksProvider } from "./Context/tasks.context";
import { BrowserRouter, Route, Switch } from "react-router-dom";
function App(props) {
const getTask = props => {
return <TaskDetail />;
};
return (
<>
<LanesProvider>
<TasksProvider>
<Navbar />
<Board /> --> Remove this component from here
<BrowserRouter>
<Switch>
<Route exact path="/" render={() => <Board />} />
<Route exact path="/board" render={() => <Board />} />
<Route exact path="/board/:taskName" render={() => getTask()} />
</Switch>
</BrowserRouter>
</TasksProvider>
</LanesProvider>
</>
);
}

Categories

Resources