Strange react-router v4 behavior with parent paths - reactjs

Backstory:
I'm building this simple application and i want to make it have pretty urls with react-router v4.
I've got 3 main components: {Home}, {List}, {Hotel}:
{Home} Component - a simple component where i can select country, datefrom and dateto and route myself to {List}.
Current path example: http://url.com/
{List} Component - A heavy component with a cards full of hotels with links to /hotel/ route.
Current path example: http://url.com/list/country/?datefrom=2019-01-01?dateto=2020-01-01
{Hotel} Component - Most far part of the app, heavy component with hotel information and list of prices split by day.
Current path example: http://url.com/hotel/country/hotel-name/?datefrom=2019-01-01?dateto=2020-01-01
The problem: What i'm trying to do is replace /list/ and use /hotels/ for a {List} component, so i would have somewhat of a hierarchy in url structure.
But once i tried to change /list/ -> /hotels/ for a {List} component route, my whole app breaks and i'm greeted with lots and lots of errors from {Hotel} component, this happens when i try to route myself from {Home} component to {List}.
What i've tried: i've tried to use <Switch> component, it makes {Home} -> {List} route work, but when i try to route myself any further to a {Hotel} component, it actualy render at the bottom of the page and doesn't replace my {List}
Here's my app.js file that gives me strange behavior...
import React from "react";
import { Route, BrowserRouter as Router } from "react-router-dom";
import Home from "./Home";
import List from "./List";
import Hotel from "./Hotel";
import './styles/app.scss';
class App extends React.Component {
render() {
return (
<Router>
<div className="app">
<Route path="/" component={Home} exact />
<Route path="/hotels/:selectedCountry/:datefrom?:dateto?" component={List} />
<Route path="/hotels/:selectedCountry/:selectedHotel:datefrom?:dateto?" component={Hotel} />
</div>
</Router>
);
}
};
export default App;

Hotel and List refer to the same resource, a hotel, but Hotel refers to a single hotel, i.e. is singular, while List refers to an index of hotels, i.e is plural. Usually, routing is done by having a singular and a plural route.
Example taken from GitHub:
URL of a list of commits: https://github.com/facebook/react/commits
URL of a single commit: https://github.com/facebook/react/commit/ec6691a6
In your case it would be:
<Route path="/hotels/your-search-params here" component={List} />
<Route path="/hotels/:hotelId:" component={Hotel} />

Your route definition is not correct.
e.g. take a look at the route path /hotels/:country/:id/:fromDate/:toDate, so a url like this /hotels/usa/123/2019-01-01/2019-12-30 will map correctly to route params and you can access these values in your component like this.props.match.params.id etc. but if you want to take the query params approach then you need to add & sign in between two params like /hotels?country=usa&id=123&fromDate=2019-01-01&toDate=2019-12-30 and then you will access it from window.location.href and parse the query parameters or use npm package like query-params to parse. In this scenario your Route path will be just /hotels

Related

How to only show the view and not the (view + links) upon clicking the links?

I have written a code which upon clicking the link routes to the view. But the links don't disappear. Please guide me on how I could only let the view be shown and not the links. I am sharing images for more clarification
App.js
import React, {Component} from 'react';
import {BrowserRouter, Route, Link, Routes} from 'react-router-dom';
import Buyer from './Container/Buyer/Buyer';
import Seller from './Container/Seller/Seller';
import classes from './App.css';
class App extends Component{
render(){
return(
<BrowserRouter>
<div className={classes.App}>
<p>Shop</p>
<ul>
<li><Link to='/buyer'>I want to Buy</Link></li>
<li><Link to='/seller'>I want to Sell</Link></li>
</ul>
<Routes>
<Route path="/buyer" element={<Buyer/>} />
<Route path="/seller" element={<Seller/>} />
</Routes>
</div>
</BrowserRouter>
)
}
}
export default App;
Initially, I want only the links and "shop" to appear and upon clicking one of the links the "shop" and links should disappear and the view must only appear.
But in my case, the "Shop " and links do not disappear upon clicking also initially the view of the buyer also appears which should appear only after clicking the link "I want to buy".
Please let me know if more description is required for this problem.
If you want the buyer to route to another view when he clicks on a link using <Link> then you need to specify which component to render when the path matches the current path. You may use "component" attribute.
<Router>
<Route path="/buyer" component={Buyer} />
<Route path="/seller" component={Seller} />
</Router>
Your 'import' needs to be changed to 'router'. The same to use in the jsx to wrap your routes.
import {BrowserRouter, Route, Link, Router} from 'react-router-dom';
You may use 'render' attribute to render jsx as a component through inline function. The difference between 'component' and 'render' attribute is
that component attribute remounts the component to be rendered each time the App component here is being evaluated.
You can read the official docs for more deails:
https://v5.reactrouter.com/web/api/Route

404 page not working for nested routes in react

I'm currently working on a notes app in React and I've built a 404 page and now if I go to a route that doesn't exist it shows a 404 page
for example, if I go to the route /get-the-note/ I get a 404 page.
But the problem is that I have a route:
<Route exact path="/single-note/:id" component={Singlenote}></Route>
which needs an id and if I put the correct id like I have a note with id no 2 and if I go to the route /single-note/2 it works but if I put an id that doesn't exist like if I put an id 120 which doesn't exist and I go to the route /single-note/120 I get a plain page instead of a 404 page. I want it show the 404 page even if the id is incorrect
here is my app.js file:
import "./App.css";
import Homepage from "./components/homepage.component";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Singlenote from "./components/singlenote.component";
import PageNotFound from "./components/404_page";
function App() {
return (
<Router>
<Switch>
<Route exact path="/" component={Homepage} />
<Route exact path="/single-note/:id" component={Singlenote}></Route>
<Route path="*"><PageNotFound /></Route>
</Switch>
</Router>
);
}
export default App;
and here is my 404 page:
import React from 'react'
const PageNotFound = () => {
return (
<div id="wrapper">
<img src="https://i.imgur.com/qIufhof.png" />
<div id="info">
<h3>This page could not be found</h3>
</div>
</div >
)
}
export default PageNotFound
The router has no way of knowing which IDs do and do not exist.
It's up to your Singlenote to render 404 content if there is no such ID.
For the last route in the Switch, you don't need the path at all, by the way.
<Route component={PageNotFound} />
The approach I suggest for this is by modifying your Singlenote component, with a useEffect hook, that checks if the id provided exists or not, only once on mount (useEffect(() => { code for check }, []);). In the event that the id does not exist, you can redirect the execution to your 404 component, by using history (e.g. history.push('*'), where * is used as the path to redirect to, you could use something else that is not covered in the routes, so it will go to 404).
I have to add that this is not a good approach, I would personally go with a notification or other indicator displayed when accessing your Singlenote component with an id that does not exist (again with useEffect), which informs the user that no results or data were found for the given id.

Route path is not working properly i tried to shows chats on the basis roomId but i can not work properly

I am trying to Render chats on the basis Room ID but when I try the URL it does not show my chat component on screen. I tried the exact path method which generally resolves this problem. Here is my router path code:
import React from 'react'
import './Messenger.css';
import Messenger_Sidebar from '../Messenger_Components/Messenger_Sidebar';
import Chat from '../Messenger_Components/Chat'
import {BrowserRouter as Router,Route,Switch } from 'react-router-dom';
<Router>
<Switch>
<Messenger_Sidebar/>
<Route path="/Messengger/t/:roomId" >
<Chat/>
</Route>
</Switch>
</Router>
[I talking about this URL In general case by using Route path is work fine but in my case it is not work for me][1]
I did NOT get what you are asking for , but if you want to render chat component
<Route path="/Messengger/t/:roomId" children={<Chat />}/>
//or
<Route path="/Messengger/t/:roomId" component={Chat}/>
then use "useParams" hock to getting roomId
let { roomId } = useParams();
i hope it works

How to handle infinite Links with react

I'm currently building a recipe book website based on ReactJS and react-router.
All my informations is saved in JSON and I'm handling all that using axios.
Now my question is, I have a grid with all my recipes, when I click on one is uses a Link to redirect me to another page, like this :
<Link to={'/' + name} className="recipe-styler" id={name}>
How can I redirect this so it will open a page and load the information of that.
I was thinking of just redirecting it to /detailedRecipe for example and parsing all the informations throught the Link, but I don't know if that is possible.
This is a combination of dynamic routing with react-router-dom and using match params.
First, let's say you have 3 routes in the app, List view, Details view and a fallback route (error page for example). It would look something like this:
<Router>
<Switch>
<Route exact path="/recipes" component={ListComponent} />
<Route path="/recipes/:id" component={DetailsComponent} />
<Route component={ErrorPage} />
</Switch>
</Router>
Now, you can set the links inside your grid to be something like this:
<Link to={`/recipes/${item.id}`} className="recipe-styler" />
Finally, when you click on the link, and router redirects to you the DetailsComponent, you can get the link id like this.
export class DetailsComponent extends React.Component {
componentDidMount() {
const { match } = this.props;
if (match) {
// This line is pseudocode.
// Use the id to get the item details from api, redux or wherever.
api.get(params.id)
}
}
render() {
...
}
}
Router will injects the match.params object when it resolves the route. Prop name from the params object depends on how you named it in the router declaration e.g.
<Route path="/recipes/:recipeId" component={DetailsComponent} /> // params.recipeId
<Route path="/recipes/:id" component={DetailsComponent} /> // params.id

Include static HTML folder/files in create-react-app

I'm using create-react-app with the react-router-dom module for my React app. I have a subfolder containing static HTML/CSS/JS that I'd like the react app to render. It could be as simple as having the router show /static/index.html.
I've searched around and there doesn't seem to be a definitive answer as to how to so this using create-react-app. Any advice is appreciated.
In order to use routing in your react app, you have to do the following:
Setup
Install react by opening the terminal/cmd, going to the current apps directory, and type in the following command: npm i react-router-dom. Hit enter and let it install.
Next, go to the index.js file, and import BrowserRouter, by adding the following line at the beginning of your code: import { BrowserRouter } from 'react-router-dom'
Then change your render thing to look like this:
ReactDOM.render(
,
document.getElementById('root')
);
What that does, is it basically tells react that App will have routing support.
Now go to your app.jsx file and import the following: import { Route, Switch } from 'react-router-dom';. (I'll explain what they all are later on.)
Now that the behind-the-scenes is setup, we can start adding routes, or paths, to out app.
Apply Routes
Go to your app.jsx file and at the render part instead of just
having components there, let's make a route. (A route just means a
url path.)
You can have components that are always there, no matter what the url path is. In order to do that, just don't have those items as routes. See the example below for more clarification.
To create a route just add the following code: <Route path="/myPath" component={myComponent} />
myComponent will display when the user goes to www.myWebsite.com/myPath.
The problem with this, is say you have a route to /myPath, and a route to / (the home page, i.e. www.myWebsite.com/), then when the user navigates to www.myWebsite.com/myPath, the home page will also display. To prevent that from happening, just wrapp all the routes in a <Switch></Switch> component.
So the final code in the render part of app.jsx will look is like this:
return (
<div className="App">
<div className="bg" />
// Will always show `Header` no matter what the rout is.
<Header/>
<Switch>
<Route path="/about" component={about} />
<Route path="/" exact component={WelcomContent} />
</Switch>
// Will always show `Footer` no matter what the rout is.
<Footer />
</div>
);
Hope this helps. Let me know if you have anymore questions.

Resources