Can't make React-Router render two different components, always render root - javascript

I have these two components that are completely independent of each other. I want to render App when I enter / and render About when I go to /#/about
I got this piece of code (but I tested quite a few others):
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Link, browserHistory } from 'react-router'
import App from './App';
import About from './About';
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={App} >
<Route path="/about" component={About} />
</Route>
</Router>
, document.getElementById('root')
);
I also tried something like
<Route path="/about" component={About} />
<Route path="/" component={App} />
And changed /about to /#/about, about
But it always render the "fallback" /, it always goes to this route, no matter what.
How can I make this app navigate properly to / and /about and render the App and the About components?
#edit
Assuming that my About component is broken, I removed the first Route and kept only the /about (kept only the /about Route) :
<Route path="/about" component={App} />
(I tried keeping About as well in a previous test) and also changed the /about to about and /#/about.
And I get this error on console:
"VM3651 bundle.js:30801 Warning: [react-router] Location "/#/about" did not match any routes"
#edit 2
I made a change, following the example #Dominic posted. I had to make some modifications to make sure both components would render. I added the {this.props.children} to all Components to understand what would happen.
//imports
ReactDOM.render(
<Router history={browserHistory}>
<Route path="/" component={About} >
<IndexRoute component={App} />
<Route path="/about" component={Other} />
</Route>
</Router>
,document.getElementById('root'));
The route http://localhost:3000/#/about is rendering:
> About > App
So it is rendering the IndexRoute, it is not getting caught by the /about.
And this is now exactly what I need, because I didn't want a root component, I wanted 2 routes to 2 different and isolated components. I need something like two sibling routes.
#edit
The About.js
import React, { Component } from 'react';
class About extends Component {
render() {
return (
<div>
About page
{this.props.children}
</div>
);
}
}
export default About;
Solution:
Since I'm using a HASH (#) in the URL, I should use hashHistory from React Router in the <Router history={hashHistory}>

You're confusing how routes work - About is a child of the App route, so in order to render About, it has to render App.
In other words your App component is the "shell" and all components under it render INSIDE it (via props.children).
You should add another route to render /.
import { ..., IndexRoute } from 'react-router'
<Route path="/" component={App} >
<IndexRoute component={Home} />
<Route path="about" component={About} />
</Route>
Your App does not contain route specific content, it would be something more like this:
<div id="app">
<nav>app navigation</nav>
<main class="route-content">{props.children}</main>
</div>
Docs: https://github.com/ReactTraining/react-router/blob/master/docs/guides/RouteConfiguration.md#adding-an-index

Those routes look correct to me. Are you getting any errors in the console? Maybe your About component is undefined and thus not rendering. Can you post your About component?

Related

react-router-dom 6.8.1 and react 18.2.0 <Link> only updated URL

I'm using react-router-dom 6.8.1 and react 18.2.0 and trying to set up browser router using the createBrowserRouter() and createRoutesFromElements() functions. I'm then rendering my browser router using the <RouterProvider> component, and the front page of my website displays fine (the App component does). For some reason, any react-router-dom <Link> components I place in my components appear on the front page, but when I click them, only the URL changes, and it does not update the UI. What's weird is that if I use an <Outlet>, the UI from the child routes will display when I click any links, but that's not what I want. I need to navigate to a separate page.
Here's where I'm creating the browser router:
import * as ReactDOM from 'react-dom/client';
import {
createBrowserRouter,
createRoutesFromElements,
Route,
RouterProvider,
} from 'react-router-dom';
import App from './app/app';
import ParticipantProfile from './app/profiles/participantProfile';
const browserRouter = createBrowserRouter(
createRoutesFromElements(
<Route path="/" element={<App />}>
<Route path="profile" element={<ParticipantProfile />} />
</Route>
)
);
const root = ReactDOM.createRoot(
document.getElementById('root') as HTMLElement
);
root.render(<RouterProvider router={browserRouter} />);
Here's where I create my <Link>:
import { Link } from 'react-router-dom';
import { createTheme } from '#mui/material/styles';
const theme = createTheme();
function App() {
return <Link to="profile">Profile</Link>;
}
export default App;
I'm tried rendering the <BrowserRouter> component itself instead of using createRoutesFromElements, but same results. Changing the path from profile to /profile also seems to do nothing.
If you want each route to map to a different component (without layout nesting), there is no need to wrap them all under a single <Route> element.
<>
<Route path="/" element={<App />} />
<Route path="/profile" element={<ParticipantProfile />} />
</>
Alternatively, only specify the element on the child route.
<Route path="/">
<Route index element={<App />} />
<Route path="profile" element={<ParticipantProfile />} />
</Route>

Page Not Found Component displaying on all pages?

I have just about completed my first real React JS project except for one bug. My 404/Page Not Found component is displaying on all pages. I have looked all over the internet and through multiple similar questions here on SO, but I am still at a loss of how to fix this problem. Here is the relevant code (with parts irrelevant to the issue removed; I can provide more code if it is necessary):
Module imports:
import React, { Component } from 'react';
import { BrowserRouter as Switch, Route, Router } from "react-router-dom";
State/login functions/authorized pages route guards here:
render() {
return (
<div>
<Router history={history} >
<Switch>
<Route render={(props) => (<HeaderNavbar {...props} handleLogin={this.handleLogin} handleLogout={this.handleLogout} loggedInStatus={this.state.loggedInStatus} role={this.state.role} key="header"/>)}/>
<Route exact path="/" component={TitlePage} />
<Route exact path="/register" component={Register} />
<Route exact path="/login" render={(props) => (<Login {...props} handleLogin={this.handleLogin} key="login" />)}/>
{this.state.role === "Student" ? (
this.studentAuthorizedPages()) :
null}
<Route exact path="/profile" component={UserProfile} />
{this.state.role === "Instructor" ? (
this.instructorAuthorizedPages()) :
null}
{this.state.role === "Administrator" ? (
this.adminAuthorizedPages()) :
null}
<Route component={PageNotFound} />
{/* <Route path='/404' component={PageNotFound} />
<Redirect to="/404" /> */}
</Switch>
</Router>
</div>
);
}
}
I believe this issue has something to do with {Switch}'s direct parent-child requirement, but I'm not sure.
So far I have tried:
Adding additional <Switch></Switch> around other parts of the code inside <Switch>. I tried this to see if it was a parent-child issue; but the bug remained.
Removing the line with HeaderNavbar in it.
Writing the {PageNotFound} route as either of the following:
Route path="*" component={PageNotFound}
Route path="" component={PageNotFound}
Using a Redirect statement (as is commented out in the code above). This prevented the app from displaying the {PageNotFound} component on every page, but then the app routed to the {PageNotFound} component on initial load, any page refresh or when a user logs out (which makes sense because logging out Routes the user back to the title page; hence basically the same as an initial load).
These are the main approaches I have tried in addition to some other smaller changes which didn't amount to anything.
I am using:
React 16.13.1
React-Router 5.1.2
Any help would be greatly appreciated.
You messed up with Switch, BrowserRouter and Router:
Change
import { BrowserRouter as Switch, Route, Router } from "react-router-dom";
to
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
according to this pattern:
<Router> // or BrowserRouter
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/topics">
<Topics />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</Router>
see here
If you want to use history prop, change BrowserRouter to just Router. Docs:
import { Router, Route, Switch } from "react-router-dom";

Can't get react-router-dom to work (seeing blank page)

This is my App component that has 3 child components: Home, Contact and Procedures. I'm trying to make each child component into its own url route.
However right now I'm just seeing a blank page
FYI- I'm using react-router-dom#6.0.2
import {BrowserRouter, Routes, Route} from 'react-router-dom';
import Home from './Home.js'
import Contact from './Contact.js'
import Procedures from './Procedures.js'
import './App.css';
function App() {
return (
<BrowserRouter>
<Routes>
<Route exact path="/" component={Home} />
<Route path="/procedures" component={Procedures} />
<Route path="/contact" component={Contact} />
</Routes>
</BrowserRouter>
);
}
export default App;
In react-router-dom version 6 you should use element instead of component, also be sure to reference the element you want to render as JSX. By the way, there is no longer any "exact" attribute.
Should look like this on your code:
<Route path="/" element={<Home />} />

React Router - Stay at the same page after refresh

I'm learning React. I have page with 4 subpages and i use React Router to go through those pages. Everything works fine except for reloading page. When i go from page "home" to "about" or other it's ok, but when i refresh page then it render again page "about" for a second and then it change page to home (home is default/first page).I want it to stay at that page which is currently rendered, not go back to home after every refresh.
There is my code in index.js file where i render whole app and use router:
<Provider store={store}>
<Router path="/" history={browserHistory}>
<Route path="/home" component={App}>
<Route path="/" component={Home}/>
<Route path="/allhotels" component={AllHotels}/>
<Route path="/addhotel" component={AddHotel} />
<Route path="/about" component={About} />
</Route>
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Router>
</Provider>, document.getElementById('root')
In "App" i have Navigation and there i render rest of conent from Home, AllHotels etc.
There is code from App.jsx
class App extends Component {
render() {
return (
<div className="app-comp">
<Navigation />
<div> {this.props.children}</div>
</div>
)
}
}
I also attach gif which shows my problem.
https://gifyu.com/image/boMp
In backend i use Firebase if it's important.
Thanks in advance.
I found the reason of my problem. I use also Firebase in my project and it causes the problem.
Thanks guys for help.
EDIT ======================================================================
Mabye I will write how I've fixed my problem and what was the reason of it.
So i was checking if user is logged in or not in auth method. And there if user was authorized I was pushing / to browserHistory.
It was mistake because every refresh method was executing and then also redirection was called as well.
Solution is just to check if during executing auth method I'm on Signin page or not. If it is Signin page then I'm pushing / to browserHistory but if not then just don't push anything.
firebaseApp.auth().onAuthStateChanged(user => {
if (user) {
let currentPathname = browserHistory.getCurrentLocation().pathname;
if( currentPathname === "/" || currentPathname === "/signin"){
browserHistory.push('/');
}
const { email } = user;
store.dispatch(logUser(email));
}
else {
browserHistory.replace('/signin');
}
})
I know that it's not pretty solution but it works and it was only home project which was created to learn react. (btw this project is using old react router 3.0 so probalby now using browserHistory is deprecated)
Check that firebase does not interfares with the client side routes :P
You can use Index routes to achieve this.
You have your navigation i.e the layout of all pages in your app component so make it the root route.
Then you want your home route to be your default route so make it your Index route.
You need to import IndexRoute from react-router package (from which you import Route).
Add this-
import { Router, Route, IndexRoute } from 'react-router';
and then make your routes like below.
Use this-
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={App}>
<IndexRoute component={Home} />
<Route path="/home" component={Home}/>
<Route path="/allhotels" component={AllHotels}/>
<Route path="/addhotel" component={AddHotel} />
<Route path="/about" component={About} />
</Route>
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Router>
</Provider>, document.getElementById('root')
it's a Server-side vs Client-side issue
check the following thread, it might give you some insights.. React-router urls don't work when refreshing or writting manually
Below example you can refer for :
React Router Navigation
Browser Refresh Issue.
Browser Back Button Issue.
Please make sure you have installed react-router-dom
If not installed. Use this command to install npm i react-router-dom
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Page1 from "./Page1";
import Page2 from "./Page2";
const rootElement = document.getElementById("root");
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route exact path="/" component={Page1} />
<Route path="/page2" component={Page2} />
</Switch>
</BrowserRouter>,
rootElement
);
Page1.js
import React from "react";
import {Link } from "react-router-dom";
function Page1() {
return (
<div>
<p>
This is the first page.
<br />
Click on the button below.
</p>
<Link to="/page2"><button>
Go to Page 2
</button>
</Link>
</div>
);
}
export default Page1;
Page2.js
import React from "react";
function Page2() {
return (
<div>
<p>This is the second page.</p>
</div>
);
}
export default Page2;
Add into your webpack.config.js this option
devServer: {
historyApiFallback: true
},
Route tag returns the first matching component.
I think you have interchanged the paths of home and app component.
try this.
<Provider store={store}>
<Router path="/" history={browserHistory}>
<Route path="/" component={App}>
<Route path="/home" component={Home}/>
<Route path="/allhotels" component={AllHotels}/>
<Route path="/addhotel" component={AddHotel} />
<Route path="/about" component={About} />
</Route>
<Route path="/signin" component={SignIn} />
<Route path="/signup" component={SignUp} />
</Router>
</Provider>, document.getElementById('root')

How do I pass Redux props to a separate component in a different Route with React Router v4?

I'm creating a real time chat app with react, react router v4 and redux. The problem is that, as you may know, react router v4 changes a lot of stuff and nesting routes is not working for me.
So I have this code with a nested route that is not working:
<Route path='/' component={App}>
<Route path="/user" component={AddUser}/>
</Route>
It's giving me this error Warning: You should not use <Route component> and <Route children> in the same route; <Route children> will be ignored.
Where component={App}, in the first <Route path='/' is a redux connect:
const App = connect(mapStateToProps, mapDispatchToProps)(Header)
So my component App has all the the props I need. All works fine except by the fact that I need to pass those props from App to the nested route component AddUser.
How do I pass the redux props to a separate component in a different Route?
With react-router v4 when we need nested routes, we don't nest Routes. Instead, we put them inside nested components. You can read about this more here: Nested routes with react router v4
In your case, you can put your "/user" route inside the App component and then use render instead of component. So you can pass your App props to AddUser as usual.
<Route path='/' component={App}/>
App.js
class App extends Component{
//...
render(){
return(
//....
<Route path="/user"
render={() => <AddUser myProp={this.props.myAppProp}/>}/>
//....
)
}
}
I found a solution reading this blog post: https://medium.com/#5XvYrLT7/react-server-side-rendering-with-react-router-3-x-74cf87919b3
With react-router v4 you don’t do this any more, don’t nest :
<Route component={App}>
<Route component={Index} />
<Route component={About} />
</Route>
You do it like this now. App embeds your routes as-is:
<App>
<Switch>
<Route exact path="/" component={Index} />
<Route path="/about" component={About} />
</Switch>
</App>

Categories

Resources