How can I navigate to another page in react? - javascript

I use react-router-dom, but when i click on the button, the page is rendered on top of the main one.
I do not need a full-fledged menu with a page transition. I have a button in the component and when I click it, I need to go to the next pageenter image description here
enter image description here
import React from "react"
import { BrowserRouter as Router, Route, Routes, Link } from 'react-router-dom'
import Profile from "../../profile/profile"
import "./UserBlock.scss"
const UserBlock = ({name,city,company}) => {
return (
<Router>
<div className="userBlock">
<div className="userBlock__info">
<div><strong>ФИО: </strong>{name}</div>
<div><strong>Город:</strong> {city}</div>
<div><strong>Компания:</strong> {company}</div>
<button><Link to="/profile">Подробнее</Link></button>
</div>
</div>
<Routes>
<Route path="/App" element={<App/>}/>
<Route path="/profile" element={<Profile/>}/>
</Routes>
</Router>
)
}
export default UserBlock
App.JS
return(
<div className='usersList'>
<div className='usersList__sidebar'>
<span>Сортировка</span>
<SortButton button={sortCity} text="по городу" />
<SortButton button={sortCompany} text="по компании"/>
</div>
<div className="usersList__lists">
<h3>Список пользователей</h3>
{isLoaded ? <img src={preloader} alt="preloader"/> : (
<div className="usersList__items">
{users.map(user => (
<div className="usersList__userCard">
<UserBlock
key={user.id}
name={user.name}
city={user.address.city}
company={user.company.name}/>
</div>
))}
<span>Найдено {count} пользователей</span>
</div>)}
</div>
</div>
)

The <Router> needs to go around everything that you want to change when you navigate.
The picture suggests that you have something like:
<main>
{ users.map(user => <UserBlock {...user} /> }
</main>
in a parent component.
You need to do your routing there and not inside each one of the UserBlocks.

Related

Hide component on button click in React using React Router

In a function, I have a button that displays a component on click. How do I hide this component when clicking on that button again (which would work like a toggle)?
<Link to="/">
<div className="navigation">
<button
className="about-button"
>
About
</button>
</div>
</Link>
<Switch>
<Route path="/" exact>
<HomePage />
</Route>
</Switch>
Your doing this a bit different then how you normally would approach this. Let me write a quick component from scratch to show you the idea...
import React, { useState } from 'react'
export default const ExampleComponent = () => {
const [showElem, setShowElem] = useState(true)
return (
<div>
{ showElem && <h1>Hello</h1> }
<Button onClick={() => {
setShowElem(!showElem)
}} />
</div>
)
}
...You'll have to excuse the formatting I typed this up right here.
I understand now that toggling is not recommended with React Routing.

How do I keep App() level state from resetting with react-router-dom in React.js?

I have a hook that changes the background color of my app. I would like the background color to stay changed when navigating through the site, but the Router resets this state back to its original useState of 'white'. How do I implement this correctly?
Created with create-react-app.
Edited to show minimum reproducible example:
import React, { useState } from 'react';
import { Route, Switch, BrowserRouter } from 'react-router-dom';
import './App.css';
export default function App() {
const [color, setColor] = useState('white');
function changeBackground(value) {
setColor(value);
};
return (
<div className={color}>
<BrowserRouter>
<Navbar changeBackground={changeBackground} />
</BrowserRouter>
</div>
);
};
function Navbar(props) {
return (
<div>
<button onClick={() => props.changeBackground('red')}>
Change Background Color
</button>
<div>
Page 1
</div>
<div>
Page2
</div>
<Switch>
<Route exact path="/page1"><Page1 /></Route>
<Route exact path="/page2"><Page2 /></Route>
</Switch>
</div>
);
};
function Page1() {
return (
<div>
Page 1
</div>
);
};
function Page2() {
return (
<div>
Page 2
</div>
);
};
/* App.css */
.white {
background-color: white;
}
.red {
background-color: red;
}
Previous code before adding minimum reproducible example:
import React, { useState } from 'react';
import { Route, Switch, BrowserRouter } from 'react-router-dom';
import './App.css';
import './assets/fonts/fonts.css';
import Navbar from './components/Navbar';
import Design from './components/Design';
import Develop from './components/Develop';
import Else from './components/Else';
import DesignTest from './pages/DesignTest';
function App() {
const [backgroundColor, setBackgroundColor] = useState('white');
function changeBackground(value) {
setBackgroundColor(value);
};
return (
<div className={`w-screen min-h-screen ${backgroundColor}`}>
{/* <Router> */}
<Navbar changeBackground={changeBackground} />
<BrowserRouter>
<Switch>
<Route exact path="/"></Route>
<Route exact path="/design"><Design /></Route>
<Route exact path="/develop"><Develop /></Route>
<Route exact path="/else"><Else /></Route>
<Route exact path="/design/test"><DesignTest /></Route>
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
function Navbar(props) {
return (
<div className="w-screen h-screen inline-grid grid-cols-12 grid-rows-6 tuffyBold tracking-widest">
<div className="row-start-1 row-end-3 col-start-1 col-end-7 text-right mt-auto mb-auto text-5xl">
TITLE
</div>
<div className="row-start-3 row-end-4 col-start-7 col-end-13 test-left mt-auto mb-auto text-4xl">
<a href="/design">
DESIGN
</a>
</div>
<div className="row-start-4 row-end-5 col-start-7 col-end-13 test-left mt-auto mb-auto text-4xl">
<a href="/develop">
DEVELOP
</a>
</div>
<div className="row-start-5 row-end-7 col-start-7 col-end-13 test-left mt-auto mb-auto text-4xl">
<a href="/else">
EVERY<br />THING<br />ELSE
</a>
</div>
<div className="row-start-1 row-end-3 col-start-7 col-end-13 mt-auto mb-auto ml-auto mr-auto">
<div className="circle white" onClick={() => props.changeBackground('white')}></div>
</div>
<div className="row-start-3 row-end-4 col-start-1 col-end-7 mt-auto mb-auto ml-auto mr-auto">
<div className="circle yellow" onClick={() => props.changeBackground('yellow')}></div>
</div>
<div className="row-start-4 row-end-5 col-start-1 col-end-7 mt-auto mb-auto ml-auto mr-auto">
<div className="circle blue" onClick={() => props.changeBackground('blue')}></div>
</div>
<div className="row-start-5 row-end-6 col-start-1 col-end-7 mt-auto mb-auto ml-auto mr-auto">
<div className="circle dark" onClick={() => props.changeBackground('dark')}></div>
</div>
</div>
);
}
export default Navbar;
.yellow {
background-color: #CDB900;
color: black;
}
.blue {
background-color: #009CCD;
color: black;
}
.dark {
background-color: #4B394E;
color: white;
}
.white {
background-color: white;
color: black;
}
I found my issue. I was using <a href="/#"> instead of importing Link from react-router-dom, causing the entire page to re-render. Here is the version that worked as I intended:
import React, { useState } from 'react';
import { Route, Switch, BrowserRouter, Link } from 'react-router-dom';
import './App.css';
export default function App() {
const [color, setColor] = useState('white');
function changeBackground(value) {
setColor(value);
};
return (
<div className={color}>
<BrowserRouter>
<Navbar changeBackground={changeBackground} />
</BrowserRouter>
</div>
);
};
function Navbar(props) {
return (
<div>
<button onClick={() => props.changeBackground('red')}>
Change Background Color
</button>
<div>
<Link to="/page1">Page 1</Link>
</div>
<div>
<Link to="/page2">Page2</Link>
</div>
<Switch>
<Route exact path="/page1"><Page1 /></Route>
<Route exact path="/page2"><Page2 /></Route>
</Switch>
</div>
);
};
function Page1() {
return (
<div>
Page 1
</div>
);
};
function Page2() {
return (
<div>
Page 2
</div>
);
};
/* App.css */
.white {
background-color: white;
}
.red {
background-color: red;
}
I had the same issue of complete app state refresh as I click on the navbar for a route change. It turned out that the issue was due to not using Link component provided by react router.
In my case I was using bootstrap navbar components. The code that I got from bootstrap site creates navbar link like this:
<Nav.Link href="/home">Home</Nav.Link>
This navigation through 'href' is the problem here. So in order to overcome this issue I wrapped Nav.Link inside LinkContainer. This allowed me to remove href from Nav.Link and I provided the route url using 'to' property in LinkContainer.
<LinkContainer to="/home">
<Nav.Link>Home</Nav.Link>
</LinkContainer>
In order to use LinkContainer I had to install and import it.
npm install react-router-bootstrap
import { LinkContainer } from "react-router-bootstrap";
Because your Navbar is outside the router component, meaning everything you click something it's actually reloading the page instead of being captured by react-router. Move the navbar component inside browser router:
return (
<div className={`w-screen min-h-screen ${backgroundColor}`}>
{/* <Router> */}
<BrowserRouter>
<Navbar changeBackground={changeBackground} />
<Switch>
<Route exact path="/"></Route>
<Route exact path="/design"><Design /></Route>
<Route exact path="/develop"><Develop /></Route>
<Route exact path="/else"><Else /></Route>
<Route exact path="/design/test"><DesignTest /></Route>
</Switch>
</BrowserRouter>
</div>
);
It is seems that something trigger re-render the whole App. Probably React Developer Tools can help you to find that place in code.
I have created an isolated example - https://codesandbox.io/s/solitary-wood-8oi66?fontsize=14&hidenavigation=1&theme=dark&file=/src/App.js
In this example value with color from the hook also saves into the browser LocalStorage, and use as a default value for the first render, so it makes it possible to keep the background color after reloading the page. Maybe this is what you want to achieve. but I'm not sure.
const defaultColor = localStorage.getItem("bgColor");
const [backgroundColor, setBackgroundColor] = useState(
defaultColor || "white"
);
function changeBackground(value) {
setBackgroundColor(value);
localStorage.setItem("bgColor", value);
}

Router for specific component is not woking

I want to route specific component in other component but when I click on the link other components are disappeared
import React from 'react';
import { Route, Switch, BrowserRouter } from 'react-router-dom';
import Sidebar from '../componants/Sidebar'
import Navbar from '../componants/Navbar';
import Router from '../Routers/Routers'
import Answer from './Answer';
import Feed from './Feed'
const Layuot = () => {
return (
<>
<div className="container-fluid">
<Navbar />
<div className="rows row">
<div className='col-3'>
<Sidebar/>
</div>
<div className="col-9 ">
<div className="content">
<Switch>
<Route path='/feed'><Feed/></Route>
<Route path = '/answer/:q_id'><Answer/></Route>
</Switch>
</div>
</div>
</div>
</div>
</>
)
}
export default Layuot;
see output
enter image description here
See Url
enter image description here
Every component are disappeared and Feed component not ms

How to load a component on page load in ReactJS?

I have a React JS component am attempting to load into a page after a user has logged in. This secure page consist of tabs and upon clicking the tabs, content is loaded from the tabs respective component.
Currently, the main component loads when it's tab is clicked, however I'm attempting to also have that main page load automatically following user login.
This is the Code behind the master page:
import React, { Component } from 'react';
import './App.css';
import AuthService from './components/AuthService';
import withAuth from './components/withAuth';
import Footer from './components/Footer';
import Navigation from './components/Navigation';
import {
Route,
NavLink,
HashRouter
} from "react-router-dom";
import Main from './components/Main';
import Catalog from './components/Catalog ';
import Calendar from './components/Calendar';
const Auth = new AuthService();
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<div className="App-title"><h2>Catalog</h2></div>
<div>
<p className="App-logout">
<button type="button" className="form-submit" onClick={this.handleLogout.bind(this)}>Logout</button>
</p>
</div>
</div>
<div className="App-divider"></div>
<div>
<Navigation />
</div>
<div className="App-content">
<HashRouter>
<Route exact path="/main" component={Main} />
</HashRouter>
<HashRouter>
<Route path="/catalog" component={Catalog} />
</HashRouter>
<HashRouter>
<Route path="/calendar" component={Calendar} />
</HashRouter>
</div>
<div>
<Footer />
</div>
</div>
);
}
handleLogout() {
Auth.logout()
this.props.history.replace('/login');
}
}
export default withAuth(App);
Am still new to React JS, could I get some help with this? ...Thanks
You probably should separate your unauthenticated views and authenticated views.
Have a login page that stores auth credentials however you'd like, (redux, locally, cookies, etc) then create a route that only shows once the user has auth...
<Route exact path="/login" component={() => !this.props.auth ? <LoginPage /> : <Redirect to="/HomePage" />}
/>
// You could also use !this.state.auth, or any other variable you are using to handle auth.

display complete new page with react router

I have build a mobile app which shows a list of movies. Its a static for now. I want to implement a react router for routing. What i want is when user clicks on the TV Shows from the list, he/she should be directed to the detail page of that TV Show. Not on the same page(layout) where list contains. I tried to do that but when i click on the title of the TV Show i am directed nowhere. How can i do that so?The code might help for expert to know what i am wanting and where i am doing wrong.
Here is my code first
Index.js
ReactDOM.render((
<Router history={browserHistory}>
<Route path="/" component={App} >
<Route component={DetailLayout}>
<Route name="flash" path="/flash" component={Flash} />
</Route>
</Route>
</Router>
), document.getElementById('root'));
MovieListItem.js(rendered by App.js)
const MovieListItem = ({movie}) => {
const imageUrl = movie.imageUrl;
const mainCastJoin = _.join(movie.mainCast, ', ');
return (<li className="list-group-item">
<div className="video-list media">
<div className="media-left">
<img className="media-object" src={imageUrl} alt={movie.title} />
</div>
<div className="media-body">
<div className="media-heading">
<Link to="flash"><h4 className="title">{movie.title}</h4></Link>
</div>
<div className="main-cast">
<ul id="cast-list">
<li className="list-item">
{mainCastJoin}...
</li>
</ul>
</div>
<div className="reviewer">
<img className="img-responsive reviewer-img" src={imdb} alt="{movie.title}" />
<div className="imdbScore">
{movie.imdb}
</div>
<img className="img-responsive reviewer-img" src={rottenTomatoes} alt="{movie.title}" />
<div style={{verticalAlign:'middle', display:'inline'}} className="rottenTomatoesScore">
{movie.rottenTomatoes}
</div>
</div>
</div>
</div>
</li>
)
};
export default MovieListItem;
Flash.js
import React, {Component} from 'react';
export default class Flash extends Component {
render() {
return (
<div>Detail page of Flash will be shown here with different Layout as in second image i have attached</div>
);
}
}
DetailLayout.js
export default class DetailLayout extends Component {
render() {
return (
<div>MyComponent</div>
);
}
}
When title of TV Show is clicked, i want to show its detail page which has completely different layout.
UPDATE
I dont know how but this works
ReactDOM.render((
<Router history={browserHistory}>
<Route path="/" component={App} >
</Route>
<Route path="detail" component={DetailLayout}>
<Route name="flash" path="/flash" component={Flash} />
</Route>
</Router>
), document.getElementById('root'));
In MovieListItem.js if i change to it works.
You are setting your flash route as a child of DetailLayout but it renders only MyComponent and has no children. Just include {this.props.children} in DetailLayout.
Set link in your MovieItemList as <Link to="/flash>
React router searches for all the routes and then renders the route it matches,and since we have added a /flash in the route it finds flash as child of / thats the reason it works.
You can also make it work by using detail/flash by handling the route inside flash as <Route name="flash" path="/detail/flash" component={Flash} />
export default class DetailLayout extends Component {
render() {
return (
<div>
<div>MyComponent</div>
<div>{this.props.children}</div>
</div>
);
}
}
Route
ReactDOM.render((
<Router history={browserHistory}>
<Route path="/" component={App} >
<Route name="detail" path="detail" component={DetailLayout}>
<Route name="flash" path="/flash" component={Flash} />
</Route>
</Route>
</Router>
), document.getElementById('root'));
MovieItem.js
const MovieListItem = ({movie}) => {
const imageUrl = movie.imageUrl;
const mainCastJoin = _.join(movie.mainCast, ', ');
return (<li className="list-group-item">
<div className="video-list media">
<div className="media-left">
<img className="media-object" src={imageUrl} alt={movie.title} />
</div>
<div className="media-body">
<div className="media-heading">
<Link to="flash"><h4 className="title">{movie.title}</h4></Link>
</div>
<div className="main-cast">
<ul id="cast-list">
<li className="list-item">
{mainCastJoin}...
</li>
</ul>
</div>
<div className="reviewer">
<img className="img-responsive reviewer-img" src={imdb} alt="{movie.title}" />
<div className="imdbScore">
{movie.imdb}
</div>
<img className="img-responsive reviewer-img" src={rottenTomatoes} alt="{movie.title}" />
<div style={{verticalAlign:'middle', display:'inline'}} className="rottenTomatoesScore">
{movie.rottenTomatoes}
</div>
</div>
</div>
</div>
</li>
)
};
export default MovieListItem;

Categories