Hide component on button click in React using React Router - javascript

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.

Related

How can I navigate to another page in react?

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.

How to hide the sidebar from perticular page in react.js?

I am implementing the global navigation sidebar (left collapsible) with react but I want to exclude or hide my sidebar from some routes or components.
and when I importing it to a particular component I am loosing my component responsiveness.
import React from "react";
//more imports are here
const App = () => (
<ThemeProvider theme={theme}>
<div>
<AppToolbar />
<div className="myclass">
<SideBar>
<Route path="/" exact component={Home} />
<Route path="/setting" component={Setting} />
<Route path="/help" component={Help} />
<Route path="/about" component={About} />
</SideBar>
</div>
</div>
</ThemeProvider>
);
export default App;
Looking for the solution to hide the sidebar from Route path="/" exact component={Home} /> route.
or is there any other way to achieve the same functionality.
Looks like the routes need to be taken out from the SideBar JSX first so that routes won't be wrapped inside SideBar indefinitely.
Pass a function props to the route components which can change the state of parent component's sidebar. Then at the route where you want to hide sidebar, call that function which will take the SideBar JSX out from the DOM.
Example:
import React from "react";
//more imports are here
const App = () => {
const [showSidebar,setShowSidebar] = React.useState();
const handleToggleSideBar = () => {
//togglesidebar with useState
setShowSidebar(!showSidebar);
}
return (
<ThemeProvider theme={theme}>
<div>
<AppToolbar />
<div className="myclass">
{showSidebar && <SideBar />}
<Route path="/" exact render={(props) => <Home toggleSideBar={handleToggleSideBar } {...props} />} />
<Route path="/setting" render={//do the same thing like Home} />
</div>
</div>
</ThemeProvider>
)};
export default App;
Home.jsx
export const Home = ({toggleSideBar}) => {
useEffect(() => {
toggleSideBar();
},[]);
}

Rendering nested router view without parent router view - React.js

Hello community :) My first Q here.
(There were couple of similar questions but they didn't answer my particular code issue and I tried them to apply but without success.)
So I would like to render the child component in nested route without the parent one showing in the view
See the picture at the end --->
import React from 'react';
import {BrowserRouter, Route, Switch, Link} from "react-router-dom";
import 'bootstrap/dist/css/bootstrap.min.css';
import Routing from "./components/Routings";
export default class Browserrouting extends React.Component {
render () {
return (
<BrowserRouter>
<Routing/>
</BrowserRouter>
)
}
}
Here is the Routing component :
import About from "../views/About";
import HomeBackground from "../views/Background";
import ShelterApp from '../views/ShelterApp';
export default (props) => (
<div className="flexColumn">
<div> <ul className="flexRow center">
<li className="homeLink"><Link className="colorBrown" to="/">Home</Link></li>
<li className="homeLink"><Link className="colorBrown" to="/shelterApp">Shelter App</Link></li>
<li className="homeLink"><Link className="colorBrown" to="/about">About our site and shelter</Link></li>
</ul></div>
<Switch>
<Route exact path="/" component={() => <HomeBackground />} />
<Route path="/about" component={() => <About />} />
<Route path="/shelterApp" component={() => <ShelterApp />} />
</Switch>
</div>
)
And in ShelterApp component I have some text and imported another component which contains the links and nested routes I would like to display without showing the parent component ShelterApp:
class ShelterApp extends React.Component {
render() {
return (
<div className="flex center">
<div className="card center" style={{ "width": "25em", "height":"25em" }}>
<div className="card-body textCenter">
<h5 className="card-title paddingTitle">Welcome to our site</h5>
<h6 className="card-subtitle mb-2 text-muted"> Login or register if it's your first time</h6>
</div>
<LoginRouting match={this.props.match} />
</div>
</div>)
}
}
export default ShelterApp;
and the final child componet with the "lowest" routes in hierarchy :
class LoginRouting extends React.Component {
constructor(props) {
super(props)
this.state = {
users: []
}
}
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
};
render() {
const { match, location, history } = this.props;
return (
<div >
<div className="flexRow center">
<Button className={" loginRouting"} type={"button"} bootstrapClass={"btn btn-light"} child={<Link to="/shelterApp/login">Login form</Link>} />
<Button className={" loginRouting"} type={"button"} bootstrapClass={"btn btn-light"} child={<Link to="/shelterApp/register">Register form</Link>} />
</div>
<div>
<Route path="/shelterApp/login" render={() => <Login />} />
<Route path="/shelterApp/register" render={() => <Register />} />
</div>
</div>
)
}
}
export default withRouter( LoginRouting)
enter image description here
IMAGE with the view :
I will be thankful for any advises !
On your ShelterApp component you can create a new state called hideInfo, or something, that tracks if the user clicked on "Login form" or "Register form".
Then you can pass a props to your <LoginRouting> component.
When the user clicks on "Login form" or "Register form" you change this.hideInfo.
<LoginRouting
onShowForm={() => this.setState({ hideInfo: !hideInfo})}
match={this.props.match}
/>

React Router v4 not loading component

For some reason, my web app is not directing to the component whenever I go to the parameters. Specifically, it is not going to the Battle component.
Here is what the navigation looks:
import React from 'react';
import Header from './components/Header/Header';
import SelectPlayers from './pages/SelectPlayers/SelectPlayers';
import Popular from './pages/Popular/Popular'
import Battle from './pages/Battle/Battle'
import { BrowserRouter as Router, Route, Link, Switch } from "react-router-dom";
function App() {
return (
<Router>
<div className={'flex flex-column'}>
<Header />
<Switch>
<Route exact path={'/'} component={Popular}/>
<Route exact path={'/battle/select-player'} component={SelectPlayers} />
<Route exact path={'/results?playerOne=:playerOne&playerTwo=:playerTwo'} component={Battle} />
</Switch>
</div>
</Router>
);
}
export default App;
In the SelectPlayers component, whenever the user presses a button it runs:
import React, {useState} from 'react';
function SelectPlayers(props) {
const [playerOne, setPlayerOne] = useState('');
const [playerTwo, setPlayerTwo] = useState('');
function setPlayerName(event, player){
if (player === 1){
setPlayerOne(event.target.value)
} else if (player === 2) {
setPlayerTwo(event.target.value)
}
}
function goToBattle(event){
event.preventDefault();
props.history.push(`/results?playerOne=${playerOne}&playerTwo=${playerTwo}`)
}
return (
<div className={'pa3 mh7-l mh7-m'}>
<div className="flex flex-column">
<div className={'mb1'}>
<h1 className={'mb0'}>Player One</h1>
<input onChange={(e) => setPlayerName(e, 1)} type="text" placeholder={'github username'} className={'input-reset pa1 w-100 h2 ba b--black br2'}/>
</div>
<div className="tc dark-red">
<h1>Versus</h1>
</div>
<div className={'mb3'}>
<h1 className={'mb0 mt0 tr'}>Player Two</h1>
<input onChange={(e) => setPlayerName(e, 2)} type="text" placeholder={'github username'} className={'input-reset pa1 w-100 h2 ba b--black br2'}/>
</div>
<div>
<button onClick={(e) => goToBattle(e)} className={'input-reset pa1 h2 fw1 bg-black white ba w-100 b--black br2'}>Battle</button>
</div>
</div>
</div>
);
}
export default SelectPlayers;
On the Battle component, I write some console.log stuff just to check if the Component loaded. However, whenever I go to that parameter, none of the code in my componentDidMount is running. I don't see any of the console.logs I wrote in componentDidMount in my developer console. Here is the component:
import React, {Component} from 'react';
class Battle extends Component {
constructor(props){
super(props)
}
componentDidMount() {
console.log('runngins');
console.log(this.props);
}
render() {
return (
<div className={'pa3 mh7-l mh7-m'}>
<div className="flex flex-column">
</div>
</div>
);
}
}
export default Battle;
You can see the code at this repo: https://github.com/tarekgabarin/github_compete
It would be greatly appreciated if anyone helped me.
As per your new comment that code is working without queryset, looks like there is some problem with your queryset parameters.
As suggested in comment box, don't define Router with queryset.
<Switch>
<Route exact path={'/'} component={Popular}/>
<Route exact path={'/battle/select-player'} component={SelectPlayers} />
<Route exact path={'/results'} component={Battle} />
</Switch>
In your SelectPlayers component, navigate to next page with queryset.
props.history.push("/results?playerOne=" +playerOne+ "&playerTwo=" +playerTwo)
On Battle component, use (query-string) to read the parameter. For example:
const values = queryString.parse(this.props.location.search);
const player_one = values.playerOne
const player_two = values.playerTwo
Please note that my above code is not tested.
Thanks

ReactJS Bootstrap Navbar and Routing not working together

I am trying to create a simple Webapp using ReactJS, and I wanted to use the Navbar provided by React-Bootstrap.
I created a Navigation.js file containing a class Navigation to separate the Navbar and the Routing from the App.js file. However, both parts do not seem to work. When I load the page, it is just empty, there is no Navbar. Can anyone spot a mistake?
Navigation.js:
import React, { Component } from 'react';
import { Navbar, Nav, Form, FormControl, Button, NavItem } from 'react-bootstrap';
import { Switch, Route } from 'react-router-dom';
import { Home } from './Page';
class Navigation extends Component {
render() {
return (
<div>
<div>
<Navbar>
<Navbar.Brand href="/">React-Bootstrap</Navbar.Brand>
<Navbar.Collapse>
<Nav className="mr-auto">
<NavItem eventkey={1} href="/">
<Nav.Link href="/">Home</Nav.Link>
</NavItem>
</Nav>
<Form inline>
<FormControl type="text" placeholder="Search" className="mr-sm-2" />
<Button variant="outline-success">Search</Button>
</Form>
</Navbar.Collapse>
</Navbar>
</div>
<div>
<Switch>
<Route exact path='/' component={Home} />
<Route render={function () {
return <p>Not found</p>
}} />
</Switch>
</div>
</div>
);
}
}
export default Navigation;
App.js:
import React, { Component } from 'react';
import Navigation from './components/routing/Navigation';
class App extends Component {
render() {
return (
<div id="App">
<Navigation />
</div>
);
}
}
export default App;
I tried using a NavItem containing a LinkContainer from react-router-bootstrap already, which led to the same result.
Just for completeness, Page.js:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
export const Page = ({ title }) => (
<div className="App">
<div className="App-header">
<h2>{title}</h2>
</div>
<p className="App-intro">
This is the {title} page.
</p>
<p>
<Link to="/">Home</Link>
</p>
<p>
<Link to="/about">About</Link>
</p>
<p>
<Link to="/settings">Settings</Link>
</p>
</div>
);
export const About = (props) => (
<Page title="About"/>
);
export const Settings = (props) => (
<Page title="Settings"/>
);
export const Home = (props) => (
<Page title="Home"/>
);
First of all, in your snippets it doesn't seem like you're wrapping your code in a Router, so you should make sure that you're doing that inside App or in ReactDOM.render:
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
rootElement
);
Next, your specific problem is that you're rendering react-bootstrap's Nav.Link instead of react-router's Link component, so the router is not picking up your route changes. Fortunately, react-bootstrap provides a render prop in most of its components to specify which component or element you want to render if you don't want the default. Switch to something like this:
import { Switch, Route, Link } from 'react-router-dom';
class Navigation extends Component {
render() {
return (
<div>
<div>
<Navbar>
<Navbar.Brand as={Link} to="/" >React-Bootstrap</Navbar.Brand>
<Navbar.Collapse>
<Nav className="mr-auto">
<NavItem eventkey={1} href="/">
<Nav.Link as={Link} to="/" >Home</Nav.Link>
</NavItem>
</Nav>
<Form inline>
<FormControl type="text" placeholder="Search" className="mr-sm-2" />
<Button variant="outline-success">Search</Button>
</Form>
</Navbar.Collapse>
</Navbar>
</div>
<div>
<Switch>
<Route exact path='/' component={Home} />
<Route render={function () {
return <p>Not found</p>
}} />
</Switch>
</div>
</div>
);
}
}
For those who have a problem with styling Link component from react-router-dom in react-bootstrap navbar, simply add className="nav-link", like this:
<Link to="/" className="nav-link">Home</Link>
instead of
<Nav.Link href="/">Home</Nav.Link>
I hope I'm no late to help some other people trying to solve this.
You can use the NavLink, instead of as={Link}. It will render with the same behavior of Link, but will "watch" the router URL to define which link is indeed active:
<Nav defaultActiveKey="/bills" as="ul">
<Nav.Item as="li">
<Nav.Link as={NavLink} to="/bills">Dividas</Nav.Link>
</Nav.Item>
<Nav.Item as="li">
<Nav.Link as={NavLink} to="/other">Em construção</Nav.Link>
</Nav.Item>
</Nav>
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
ReactDOM.render(
<BrowserRouter>
<App />
</BrowserRouter>,
document.getElementById('root')
);
and Navbar.js:
import React from 'react';
import {Container,Navbar,Nav,NavItem } from 'react-bootstrap';
import {Link} from 'react-router-dom';
<Nav className="ml-auto">
<NavItem> <Link className="nav-link" to="/">Home</Link> </NavItem>
<NavItem> <Link className="nav-link" to="/about">About</Link> </NavItem>
<NavItem> <Link className="nav-link" to="/contact">Contact</Link> </NavItem>
</Nav>
This resolved the: <Link> outside a <Router> error for me.
Having found myself with a project of non-trivial size, and one that already had jQuery as a dependency I was able to gracefully solve the react-router / react-bootstrap mismatch with an event listener on the document.
This has one advantage over other solutions in that it requires no changes to the current markup. However, one may need to write some additional logic guarding the history.push call depending on needs. One may also need to expand this to guard for the target attribute, e.g. target="_blank".
If jQuery is not desired, one may be able to write a vanilla JS implementation with document.addEventListener without much additional effort.
// react-router#5
// usage of history may vary depending on version
import { Router } from 'react-router-dom';
import { createBrowserHistory } from 'history';
const history = createBrowserHistory();
// IIFE scoping jQuery for us
(($) => {
// Wait for document ready
$(() => {
$(document).on('click', '[href]', (event) => {
// Only target links targeting our application's origin
if (event.currentTarget.href.indexOf(window.location.origin) === 0) {
// Prevent standard browser navigation
event.preventDefault();
const path = event.currentTarget.href.slice(window.location.origin.length);
history.push(path);
}
});
});
})(jQuery);
const Routing = (props) => (
<Router history={ history }>
...
</Router>
);
Currently, with react v18 and react-router v6.4, the approach is working for me is a bit different.
To make the links properly work with react-route use as={Link} in the Nav.Link item.
And to make the tabs highlight you need to use eventKey as described in the documentation: EventKey is used to determine and control the active state of the parent Nav
Here is an example.
Notice that the changes also affect the Navbar.Brand component.
import { Link, useLocation } from 'react-router-dom';
const AppNavbar = () => {
const location = useLocation();
const activeKey = location.pathname === '/' ? '/projects' : location.pathname;
return (
<Navbar expand="lg" className="theme-navbar">
<Container>
<Navbar.Brand as={Link} to="/">
My Projects
</Navbar.Brand>
<Navbar.Toggle aria-controls="basic-navbar-nav" />
<Navbar.Collapse id="basic-navbar-nav">
<Nav activeKey={activeKey} className="me-auto">
<Nav.Link as={Link} eventKey="/projects" to="/projects">
Projects
</Nav.Link>
<Nav.Link as={Link} eventKey="/work" to="/work">
Ongoing Tasks
</Nav.Link>
</Nav>
</Navbar.Collapse>
</Container>
</Navbar>
);
};
i think you forgot to include bootstrap css, refer to the stylesheets section of the following doc
https://react-bootstrap.github.io/getting-started/introduction/
or just add the following to ur index.html
<link
rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/4.2.1/css/bootstrap.min.css"
integrity="sha384-GJzZqFGwb1QTTN6wy59ffF1BuGJpLSa9DkKMp0DgiMDm4iYMj70gZWKYbI706tWS"
crossorigin="anonymous"
/>

Categories