Routing inside a React app with button click - reactjs

I am building a basic react app in which clicking a button should open a new page in the same tab. I have used React Router for this but that is not working for me.
I want to redirect to a state say, localhost/test , this is my index.js
import Test from './test/Test'
import { Route } from 'react-router-dom';
const myFirstElement = <>
<Button onClick={() => window.location.href='test'}>Click me</Button>
<Route path='test' element={< Test />}></Route>
</>
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(myFirstElement);
My Test.js contains
const Test = <><h1>Hello React!</h1></>
export default Test;
The problem is above code does not render anything on the screen and it doesn't show any error too. But when I remove the
<Route exact path='/test' element={< Test />}></Route>
above code, a button is rendered on the screen, clicking on the button changes the url but doesn't changes state.
Any help will be appreciated.

Issue
When the index.js file includes just a Route component it fails an invariant that checks if the Route component is rendered directly by a Routes or other Route component, and also fails an invariant check for a routing context being provided by a router component. This is why the code runs when you remove <Route path='/test' element={< Test />} />.
The other issue is with using window.location to change the URL. When this happens it reloads the page, which reloads the React app. You should use react-router-dom hooks and components to navigate within the app.
Solution
The app needs to render at least a router and wrap any Route components in the Routes. Use the useNavigate hook to access the navigate function to issue an imperative navigation action to the "/test" path.
Example:
import { BrowserRouter as Router, Routes, Route, useNavigate } from 'react-router-dom';
import Test from './test/Test'
const MyFirstElement = () => {
const navigate = useNavigate();
return (
<>
<Button onClick={() => navigate('test')}>Click me</Button>
<Routes>
<Route path='test' element={<Test />} />
</Routes>
</>
);
}
const root = ReactDOM.createRoot(document.getElementById('root')); root.render(
<Router>
<MyFirstElement />
</Router>
);

If I'm not mistaken, then you definitely need to wrap the application in a BrowserRouter.
import * as React from "react";
import * as ReactDOM from "react-dom";
import App from "./App";
import { BrowserRouter } from "react-router-dom";
ReactDOM.render(
<BrowserRouter>
{/* The rest of your app goes here */}
<App/>
</BrowserRouter>,
root
);
Routers must be wrapped with Routes
App component:
import React from 'react';
import {Navigate, Route, Routes, useNavigate} from "react-router-dom";
function App() {
return (
<div className={styles.App}>
<Routes>
<Route path="/" element={<Test/>}/>
</Routes>
</div>
);
}
export default App;

Related

I have been working on this code and the browser router is not working. the output is simply empty

import { useState } from 'react';
import About from './Container/About';
import Profile from './Container/Profile';
import {BrowserRouter as Router,Route} from 'react-router-dom'
function App() {
const [state,setState] = useState('Data')
return (
<div >
<button onClick={()=>setState('About')} >About</button>
<button onClick={()=>setState('Profile')}>Profile</button>
{state}
<Router>
<Route element={<About/>} path='/about' />
</Router>
</div>
);
}
export default App;
Why is the browser router is not working as it is showing nothing in the output?
Why is the browser router is not working as it is showing nothing in the output?Why is the browser router is not working as it is showing nothing in the output?Why is the browser router is not working as it is showing nothing in the output?
You need to update the navigation path in order to make this work. Currently you are only updating your state, which is completely decoupled from React Router.
You can either add a link component or naviagate programmatically.
The following should work in your case
import { useNavigate } from "react-router-dom";
[...]
let navigate = useNavigate();
[...]
<button onClick={()=>{ setState('About'); navigate('/about'); } } >About</button>
Or if you don't need the state for anything other than the navigation, you can remove it and replace your buttons with React Router Link components.
The router component maintains it's own state and routing context. You need to either use a Link component or the navigate function to issue an imperative navigation action. Don't forget that all the Route components need to be wrapped by the Routes component so route path matching and rendering functions.
Example:
import About from './Container/About';
import Profile from './Container/Profile';
import { BrowserRouter as Router, Routes, Route, Link } from 'react-router-dom';
function App() {
return (
<div >
<Router>
<Link to='/'>Home</Link>
<Link to='/about'>About</Link>
<Link to='/profile>Profile</Link>
<Routes>
<Route element={<h1>Home</h1>} path='/' />
<Route element={<About />} path='/about' />
<Route element={<Profile />} path='/profile' />
</Routes>
</Router>
</div>
);
}
export default App;
If you decide to use the useNavigate hook to access the navigate function in this App component then the Router will need to be higher in the ReactTree in order for the useNavigate hook and routing components in App to be able to access the routing context.

React Milti Page Routing

I am trying to make a multi page app with react routing.
I am have some questions as to how I should structure the routing in the react project.
I want to load my component in my app.js file. In my Home component I would like to have the ability to press a button which will take me to the Poems component, I want the code to be clean and structured into components, therefore I dont want to do all this in the app.js file.
If someone would explain to me how to best do this I can from there be able to route around to multiple pages afterwards depending on the page you are on. I dont want to have a global menu currently (I will want that in the Poems component later though).
Here is my current App.js file & Home.jsx component code just for a more easily adjustable experience for you guys!
Currently it is not optimized to work so if anyone knows a good routing solution for my issue, please give me an example of the routing fix.
Thanks alot
/Jacob
import React from 'react'
import { Route, BrowserRouter as Router, Routes } from 'react-router-dom'
import './App.scss'
import { Home, Poems, Favourites } from './Pages'
const App = () => {
return (
<Router>
<div className="app">
<Home />
<Routes> {/* I read that the Switch was replaces with Routes */}
<Route path="/" exact component={ Home } />
<Route path="/Poems" component={ Poems } />
<Route path="/Favourites" component={ Favourites } />
</Routes>
</div>
</Router>
)
}
export default App
import React from 'react'
import { Route, BrowserRouter as Router, Routes, Link } from 'react-router-dom'
import { Poems } from './Pages'
import './Home.scss'
const Home = () => {
return (
<Router>
<div>
<h1>Petry For All</h1>
<Routes>
<Route path="/Poems" component={ Poems } />
<Link to="/Poems">Poems</Link>
</Routes>
</div>
</Router>
)
}
export default Home
You don't need to (and actually shouldn't) duplicate the <Router> component in all of the route pages. It is only the root component that is acting as a router. So you can keep the App component the same, and then replace the Home component with the following:
import React from 'react'
import { Poems } from './Pages'
import './Home.scss'
const Home = () => {
return (
<div>
<h1>Petry For All</h1>
<Link to="/Poems">Poems</Link>
</div>
)
}
export default Home
The <Link> component resolves into an anchor element which, when clicked, navigates the user to the route passed into the to property.

react-router-dom not working as expected with routes

I'm understanding the react-router-dom library and the components that provide the routing and noticed a strange behavior as below.
Assume we have our App.js component which return JSX code as below.
import './App.css';
import ColorAdder from './ColorAdder';
import {Switch,Route} from 'react-router-dom';
function App() {
return (
<Switch>
<ColorAdder/>
<Route path="/hello" exact>
<p>Hello</p>
</Route>
</Switch>
);
}
export default App;
Now the component ColorAdder.js also consists of Routes with Path and exact attributes declared as below.
import { Route } from "react-router-dom";
const ColorAdder = ()=>{
return (
<Route path="/hi" exact>
<p>Hi</p>
</Route>
)
}
export default ColorAdder;
The App.js is wrapped with <BrowserRouter> and what i noticed is when we test the page with url http://localhost:3002/hi it returned Hi as expected but it does n't return anything for 'http://localhost:3002/hello'.why does it behave this way ? Can anyone please explain this behavior why the Route with path hello is not identified even when it is under Switch wrapping and with Path and exact attributes
Below is the Index.js using BrowserRouter
ReactDOM.render(<BrowserRouter><App/></BrowserRouter>,document.getElementById('render'))
Versions:
react-router-dom#5,
npm - 7.20.3,
node - v16.7.0
first, its good practice to have routing logic in app.js plus don't render <ColorAdder/> inside the switch instead use the component attribute in like this:-
your App.js : -
import './App.css';
import ColorAdder from './ColorAdder';
import {Switch,Route} from 'react-router-dom';
function App() {
return (
<Switch>
<Route path="/hi" component={colorAdder} exact></Route>
// if you have other routes do like this
<Route path="/hello" component={<p>hello</p>} exact></Route>
// instead of hard coding <p>hello </p> here you can create a separate component that render the helloComponent
</Switch>
);
}
your ColorAdder.js :- it should only return the content cuz the routing logic is done in app.js
import { Route } from "react-router-dom";
const ColorAdder = ()=>{
return (
<p> h1 </p>
)
}
export default ColorAdder;
NB :- BrowserRouter should be inside index.js it should wrap the app component
<BrowserRouter>
<App />
</BrowserRouter>,

react-router-dom : updates url but does not render the new component

I am a bit lost with this issue for a whole day.
On button click the url changes but does not render the new page and I don't understand why.
I am using react-dom-router 5.2.0
INDEX JS
import {Router} from 'react-router-dom';
import history from './history';
ReactDOM.render(
<React.StrictMode>
<Router history={history}>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
APP JS
import Server from './Server';
import React from 'react';
function App() {
return (
<Server />
);
}
export default App;
SERVER JS
export default class Server extends Component
{
render()
{
return(
<div className="Homepage" >
<h1 className="header">Server</h1>
<button className="button"
onClick={() => history.push('/control')}>
Lets go
</button>
}
</div>
);
}
}
Please Note : I added <Control/> directly in the render method above and it renders the component all well .
CONTROL JS
import React, {Component} from 'react';
import Page2_View from './Page2_View';
export default class Control extends Component
{
constructor(props)
{
super(props);
}
render()
{
return(
<Page2_View/>
);
}
}
Page2_View
import React, {Component} from 'react';
const Page2_View = (props) =>
{
return(
<h1> PAGE 2 VIEW </h1>
);
}
export default Page2_View;
ROUTES JS
import {BrowserRouter as Router, Route, Redirect, Switch} from 'react-router-dom';
const Routes = () =>
{
return(
<Router>
<div>
<Switch>
<Route exact path="/test" component={Server}/>
<Redirect from = '/test' to = '/control'/>
<Route exact path="/control" component={Control}/>
</Switch>
</div>
</Router>
);
}
export default Routes;
HISTORY JS
import {createBrowserHistory as history} from 'history';
export default history();
I appreciate all the help. Thank you
I think the problem is that react-router-dom is not aware of this history.push('/control') you're doing; i.e. if you want to redirect to another route, it should be through react-router, not outside of it.
You have a few options:
Use the useHistory hook: https://reacttraining.com/react-router/web/api/Hooks/usehistory
Your button could be wrapped in a Link component: https://reacttraining.com/react-router/web/api/Link
Get the router through props with the withRouter component, as explained in: Programmatically navigate using react router V4.
I have realized what I was doing wrong and was able to solve my issue.
The key was to understand that the Router module from react-router-dom
comes with three props : path , history, and component.
So in order to redirect a page on button click all I had to do embed all my Routes between tag in the App.js
APP JS
function App() {
return (
<Router>
<Switch>
<Route exact path="/test" component={componentA}/>
<Route exact path="/test2" component={componentB}/>
</Switch>
</Router>
);
}
export default App;
And then you can use button onClick to redirect
COMPONENTA JS
<button variant="secondary"
className="button" size="lg"
onClick={() => this.props.history.push('/test2')}>
RedirectTo
</button>
Hope this will be helpful to others who come across this!
In server.js file instead of button use navlink or link from reactrouter below is a saple code
<NavLink to="/control">control</NavLink>
Import every component to routing component then use router switch and redirect statements like below
import Main from './component/Main'
import Welcome from "./component/welcome"
import { Route, BrowserRouter as Router, Switch,Redirect } from 'react-router-dom'
function App() {
return (
<Router>
<Switch>
<Redirect from="/" to="/home" exact />
<Route exact path="/home" component={Main} />
<Route path="/welcome" component={Welcome} />
</Switch>
</Router>
);}
export default App;
and in your component where you re clicking import link or nav link i prefer using navlink
and use it to redirect to page on click
import { NavLink } from 'react-router-dom'
<NavLink to="/home">home</NavLink>

The url is changing but the component is not rendered correctly?

I am having a problem, I am using react router and I will explain the situation.
I have a form to log in, with /authenticate in the url, if authentication is successed then I go to "/" ( home page ) which is doing good now, and I have two navigation bars, one on the left, the other on the top, now when I click on the links, the url changes but the components are not rendered on clicking them, but if I tap the url on the browser and click enter ( page refreshed ) the component is rendered correctly.
Here is my code :
This is the component rendered after the succesful log in, it is my main application, so The MenuGauche and MenuTop are always rendered :
import React, { Fragment } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import MenuGauche from "./MenuGauche";
import MenuTop from "./MenuTop";
import Acceuil from "./Acceuil";
import Roles from "./Roles";
const Application = () => {
return (
<Fragment>
<MenuGauche></MenuGauche>
<MenuTop></MenuTop>
<BrowserRouter>
<Switch>
<Route path="/" component={Acceuil}></Route>
<Route path="/roles" component={Roles}></Route>
</Switch>
</BrowserRouter>
</Fragment>
);
};
export default Application;
And here is my top route component ( the default component suggested by react ) :
function App(props) {
return (
<ThemeProvider theme={theme}>
<I18nProvider locale={props.language.language}>
<BrowserRouter>
<Switch>
<Route exact path="/" component={Application}></Route>
<Route path="/authenticate" component={Authentification}></Route>
</Switch>
</BrowserRouter>
</I18nProvider>
</ThemeProvider>
);
}
Why is that not working ? I would like to get any help to solve that, a solution or a proposition!
One solution is provided, it is that have to keep the BrowserRouter only in the top root component, but still nothing!
here is the modification :
import React, { Fragment } from "react";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import MenuGauche from "./MenuGauche";
import MenuTop from "./MenuTop";
import Acceuil from "./Acceuil";
import Roles from "./Roles";
const Application = () => {
return (
<Fragment>
<MenuGauche></MenuGauche>
<MenuTop></MenuTop>
<Route path="/" component={Acceuil}></Route>
<Route path="/roles" component={Roles}></Route>
</Fragment>
);
};
export default Application;
If you feel like I need to provide more code just ask for it.
the problem is that you are using two BrowserRouter component, make sure that is is used once and it is in most top level component in whole application

Resources