React-router route won't trigger - reactjs

First, i am sorry if this problem has been asked before. I am currently new to react-router, i don't know what to ask. So, i am trying to make a sidebar component in my apps, this sidebar composed of material-ui drawer, listItems. Each listItem has a link i put as its containerElement attribute value. Selecting each list does change the url, but component that each route should display won't show.
Here is my code:
App.js
import React, { Component } from 'react'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Sidebar from './components/Sidebar'
import {
BrowserRouter as Router,
Route,
} from 'react-router-dom'
var injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();
const ListItem = () => (
<div>
<h2>List Item</h2>
</div>
)
const CreateForm = () => (
<div>
<h2>Create Form</h2>
</div>
)
const SearchItem = () => (
<div>
<h2>Search Item</h2>
</div>
)
class App extends Component {
render() {
return (
<MuiThemeProvider>
<Router>
<div>
<Sidebar />
<Route exact path="/" component={ListItem}/>
<Route path="/create" component={CreateForm}/>
<Route path="/search" component={SearchItem}/>
</div>
</Router>
</MuiThemeProvider>
)
}
}
export default App;
Sidebar.js
import React, {Component} from 'react'
import Drawer from 'material-ui/Drawer'
import {List, ListItem, makeSelectable} from 'material-ui/List'
import Subheader from 'material-ui/Subheader'
import {Link} from 'react-router-dom'
let SelectableList = makeSelectable(List)
function wrapState(ComposedComponent) {
return class SelectableList extends Component {
componentWillMount() {
this.setState({
selectedIndex: this.props.defaultValue,
})
}
handleRequestChange = (event, index) => {
this.setState({
selectedIndex: index,
})
}
render() {
return (
<ComposedComponent
value={this.state.selectedIndex}
onChange={this.handleRequestChange}
>
{this.props.children}
</ComposedComponent>
)
}
}
}
SelectableList = wrapState(SelectableList)
const ListSelectable = () => (
<SelectableList defaultValue={1}>
<Subheader>Basic CRUD operation</Subheader>
<ListItem
value={1}
primaryText="List"
containerElement={<Link to='/'/>}
/>
<ListItem
value={2}
primaryText="Create"
containerElement={<Link to='/create'/>}
/>
<ListItem
value={3}
primaryText="Search"
containerElement={<Link to='/search'/>}
/>
</SelectableList>
);
class Sidebar extends Component {
render() {
return (
<Drawer>
<ListSelectable />
</Drawer>
)
}
}
export default Sidebar
Note: The selectable list implementation i copied from material-ui docs.

Your component is covered by the sidebar. Try to put some margin on the left.
import React, { Component } from 'react'
import MuiThemeProvider from 'material-ui/styles/MuiThemeProvider'
import Sidebar from './components/Sidebar'
import {
BrowserRouter as Router,
Route,
} from 'react-router-dom'
var injectTapEventPlugin = require("react-tap-event-plugin");
injectTapEventPlugin();
const ListItem = () => (
<div>
<h2 style={{marginLeft:'300'}}>List Item</h2>
</div>
)
const CreateForm = () => (
<div>
<h2 style={{marginLeft:'300'}}>Create Form</h2>
</div>
)
const SearchItem = () => (
<div>
<h2 style={{marginLeft:'300'}}>Search Item</h2>
</div>
)
class App extends Component {
render() {
return (
<MuiThemeProvider>
<Router>
<div>
<Sidebar />
<Route exact path="/" component={ListItem}/>
<Route path="/create" component={CreateForm}/>
<Route path="/search" component={SearchItem}/>
</div>
</Router>
</MuiThemeProvider>
)
}
}
export default App;

Related

Wrapper Component showing different navigation on different pages

I'm trying to make my page flexible to show different navigation bars depending on the page I'm on. When I run the page with the code presented below it shows the different navs as they should, but the actualRouteComponent is not showing the content of the route component eg. FrontpageRoute, BookRoute.
This is my App.js:
import React from 'react';
import {BrowserRouter as Router, Switch} from 'react-router-dom';
import './Mystyles.scss';
//Routes
import DynamicLayout from './layout/DynamicLayout'
import FrontpageRoute from './routes/FrontpageRoute';
import BookRoute from './routes/BookRoute';
function App() {
return (
<Router>
<div className="App">
<Switch>
<DynamicLayout
exact
path="/"
component={FrontpageRoute}
/>
<DynamicLayout
exact
path="/book"
component={BookRoute}
layout="SUB_NAV"
/>
</Switch>
</div>
</Router>
);
}
export default App;
This is my DynamicLayoutRoute.js:
import React from 'react';
import {BrowserRouter as Route} from 'react-router-dom';
import Header from './../components/Header';
import MainNavigation from '../components/MainNavigation';
const DynamicLayout = props => {
const { component: RoutedComponent, layout, ...rest } = props;
const actualRouteComponent = (
<Route
{...rest}
render={props => (
<RoutedComponent {...props} />
)}
/>
);
switch (layout) {
case 'MAIN_NAV': {
return (
<div>
<MainNavigation />
<Header />
{actualRouteComponent}
</div>
)
}
case 'SUB_NAV': {
return (
<div>
<MainNavigation />
<h2>Sub Nav</h2>
<Header />
{actualRouteComponent}
</div>
)
}
default: {
return (
<div>
<MainNavigation />
<Header />
{actualRouteComponent}
</div>
)
}
}
};
export default DynamicLayout;
and here is my MainNavigation.js:
import React, { Component } from 'react'
import { NavLink } from 'react-router-dom'
class MainNavigation extends Component {
render() {
return (
<nav className="main-navigation">
<div className="main-navigation--content">
<div className="mobil-nav">
<span>Burger</span>
</div>
<div className="link-list">
<NavLink exact to="/">Frontpage</NavLink>
<NavLink exact to="/book">Book</NavLink>
</div>
<div className="social">
<span>Instagram</span>
</div>
</div>
</nav>
)
}
}
export default MainNavigation
Can someone tell me what is wrong?
I see that in your DynamicLayoutRoute component you are accessing props as this.props. this is undefined in functional components.
Access props like this -
const DynamicLayoutRoute = props => {
const { component: RoutedComponent, layout, ...rest } = props;
...
}

Second and subsequent Route in react-router-dom is not being rendered?

I have been working with react-router-dom v4 and i am trying to make a central config for the routes with a workaround.
This is my routes.js
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import {
WebsiteFilter,
WebsiteLeaderBoard,
WebsiteGraph,
WebsiteQues
}
from "./components";
import { DashboardApp ,LeaderBoardApp} from "./containers";
const dashboardContainer = (id) => (
<DashboardApp key={id}>
<Switch>
<Route exact path="/dashboard" render={(props) => (
<>
<WebsiteFilter />
<WebsiteGraph />
<WebsiteQues />
</>
)}
/>
</Switch>
</DashboardApp>
);
const leaderBoardContainer = (id) => (
<LeaderBoardApp key={id}>
<Switch>
<Route exact path="/leaderboard" render={(props) => (
<>
<WebsiteLeaderBoard />
</>
)} />
</Switch>
</LeaderBoardApp>
);
const container = [ dashboardContainer , leaderBoardContainer ];
const Routes = () => {
return (
<BrowserRouter baseName="/">
<Switch>
{container.map((pages,id) => (
pages(id)
))}
</Switch>
</BrowserRouter>
);
};
export default Routes;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This is my DashboardApp.js
import React, { Component } from "react";
import { WebsiteHeader , WebsiteFooter} from "../components";
import PropTypes from "prop-types";
import classes from "./app.scss";
class DashBoardApp extends Component {
render() {
return (
<div className={classes.app}>
<WebsiteHeader/>
<>
{this.props.children}
</>
<WebsiteFooter />
</div>
);
}
}
export default DashBoardApp;
DashBoardApp.propTypes = {
children : PropTypes.element,
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This is my LeaderBoardApp.js
import React, { Component } from "react";
import { WebsiteHeader , WebsiteFooter} from "../components";
import PropTypes from "prop-types";
import classes from "./app.scss";
class LeaderBoardApp extends Component {
render() {
return (
<div className={classes.app}>
<WebsiteHeader/>
<>
{this.props.children}
</>
<WebsiteFooter />
</div>
);
}
}
export default LeaderBoardApp;
LeaderBoardApp.propTypes = {
children : PropTypes.element,
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
I have set my Link:
export default function HeaderLink (props) {
const { wrapperClass, dashboardClass } = props;
return (
<ul className={wrapperClass}>
<li className={[dashboardClass,classes.active].join(" ") }><Link to ="/dashboard">Dashboard</Link></li>
<li className={dashboardClass}> <Link to ="/leaderboard">Leaderboard</Link></li>
</ul>
);
}
According to this the link should work , but when i try to click the leaderboard link , it doesn't render the Websiteleaderboard component. But it always render the First route when i click the dashboard link as it's the first after switch statement.
I searched online , and thought about it a lot , but couldn't found any solution. I don't know what's the problem here.
Here's the picture of rendered routes:
First pic
Second pic
You have multiple <Switch> elements in what you're trying to do. From the docs:
When a <Switch> is rendered, it will only render the first child that matches the current location.
Docs here
Removing all the switches except the wrapper should work. However, might I suggest a cleaner approach:
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import {
WebsiteFilter,
WebsiteLeaderBoard,
WebsiteGraph,
WebsiteQues
}
from "./components";
import { DashboardApp ,LeaderBoardApp} from "./containers";
const dashboardContainer = () => (
<DashboardApp>
<WebsiteFilter />
<WebsiteGraph />
<WebsiteQues />
</DashboardApp>
);
const leaderBoardContainer = () => (
<LeaderBoardApp>
<WebsiteLeaderBoard />
</LeaderBoardApp>
);
const Routes = () => {
return (
<BrowserRouter baseName="/">
<Switch>
<Route path="/dashboard" component={dashboardContainer} />
<Route path="/leaderboard" component={leaderBoardContainer} />
</Switch>
</BrowserRouter>
);
};
export default Routes;
By doing this, your entire configuration is contained in the Routes. You could even move the components out of that file, and have your Routes contained to only the actual routes, while importing the components you want to use.

Routing in React JS on click

I am new to React and I want to navigate to another component on button click. I just want to perform a simple routing. This is the code that I tried. But I am not able to route it.
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch, Redirect } from 'react-router-dom'
import Hello from './HelloComponent';
class App extends Component {
constructor(props) {
super(props);
this.try = this.try.bind(this)
}
try = () => {
alert();
<div>
<Router>
<Route path="/hello" component={Hello} />
</Router>
</div>
}
render() {
return (
<div className="App">
<div className="container">
<button id="b1" onClick={this.try}>Click me</button>
</div>
</div>
);
}
}
export default App;
Please help me with this code to perform basic routing in react JS
You cannot return JSX to onClick handler since it won't do anything with it.
You need to configure your Routes in render in advance and use history.push to change the Route
Below is a sample code that you can refer
import React, { Component } from 'react';
import { BrowserRouter as Router, Route,Switch, Redirect} from 'react-router-dom'
import Hello from './HelloComponent';
class App extends Component {
try = () => {
this.props.history.push('/hello');
}
render() {
return (
<div className="App">
<div className="container">
<button id="b1" onClick ={this.try}>Click me</button>
<Route path="/hello" component={Hello}/>
</div>
</div>
);
}
}
export default () => (
<div>
<Router>
<Route component={App} />
</Router>
</div>
);
I recommend you look at the doc.
<Route path="/hello" component={Hello}/> will display the component Hello exactly where the <Route/> is, but I think your function will do nothing here as it returns a <div> but where does it go?
You need some sort of "higher" component that will render your routes, then call a <Link/>
Then try nesting the button inside the <Link/> ?
<Link to="/??">
<button id="b1">
Click me
</button>
</Link>
in your code
try = () => {
alert();
<div>
<Router>
<Route path="/hello" component={Hello}/>
</Router>
</div>
}
your just pushing the route and it's not a action to take you to different page
bellow code will work fine and it's good practice to place router in separate component. click here you can find this code in codesandbox
import React, { Component } from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import "./styles.css";
function RouterComponet() {
return (
<Router>
<Switch>
<Route exact path="/" component={App} />
<Route path="/user" component={User} />
</Switch>
</Router>
);
}
class App extends Component {
constructor(props) {
super(props);
}
onClick = () => {
this.props.history.push("/user");
};
render() {
return (
<div>
<h1>App component</h1>
<a onClick={this.onClick} className="link">
click here
</a>{" "}
to user page
</div>
);
}
}
class User extends Component {
constructor(props) {
super(props);
}
onClick = () => {
this.props.history.push("/");
};
render() {
return (
<div>
<h1>User Componet</h1>
<a onClick={this.onClick} className="link">
click here
</a>{" "}
to back
</div>
);
}
}
const rootElement = document.getElementById("root");
ReactDOM.render(<RouterComponet />, rootElement);
I have created a demo that brings it all together. It has three files App.js, About.js, Contacts.js. To Navigate to any component, you need to add its route in App.js, Then depending on the location of your button (About.js), wrap it with Link that helps the element navigate to the specified route. When clicked, the Contacts component should be loaded. Hope this helps. code demo
App.js
import React from "react";
import { Switch, Route, BrowserRouter } from "react-router-dom";
import About from "./About";
import Contact from "./Contacts";
function App() {
return (
<BrowserRouter>
<Switch>
<Route path="/" component={About} exact />
<Route path="/contacts" component={Contact} />
</Switch>
</BrowserRouter>
);
}
export default App;
About.js
import React from "react";
import { Link } from "react-router-dom";
function About() {
return (
<div>
<p>
Lorem Ipsum is simply dummy text of the printing and typesetting
industry.
</p>
<Link to="/contacts">
<button>click me</button>
</Link>
</div>
);
}
export default About;
Contacts.js
import React from "react";
function Contact() {
return <div>Call me!!</div>;
}
export default Contact;
This is the first SO post on google, so I'd like answer the question with updated coding style and answer:
From react v6 you use the useNavigation hook. (Reference)
import { useNavigate } from 'react-router-dom';
export const MyComponent = () => {
const navigate = useNavigate();
return (
<>
<button
onClick={() => {
navigate('/');
}}
>
click me
</button>
</>
);
};

React Router changes Link but doesnt render proper component

Hello I'm working with React Router... I have two components App.js and SideNavComponent. I want to click the link in the SideNavComponent to and travel to the correct Component.
Right now when I click on the Link it changes the URL but does not render the correct component. However if I change the URL myself the correct view renders.
App.js
import React, { Component } from 'react';
import { Col, Well, Panel } from 'react-bootstrap';
import NavbarComponent from './NavbarComponent';
import SideNavComponent from './SideNavComponent';
import Router from './Router';
class App extends Component {
render() {
return (
<div>
<div className="header">
<NavbarComponent />
</div>
<div className="body">
<Col md={3}>
<Well>
<SideNavComponent />
</Well>
</Col>
<Col md={9}>
<Panel>
<Router />
</Panel>
</Col>
</div>
<div className="footer" />
</div>
);
}
}
export default App;
SideNavComponent
import React, { Component } from 'react';
import { Nav, NavItem } from 'react-bootstrap';
import { Link, BrowserRouter, Switch } from 'react-router-dom';
class SideNavComponent extends Component {
state = {
selectedLink: 1
};
selectLink(key) {
this.setState({ selectedLink: key });
}
render() {
return (
<BrowserRouter>
<div style={{ flexDirection: 'column' }}>
<Link to="/">Home</Link>
<Link to="/device">Device</Link>
<Link to="/transform">Transformation</Link>
<Link to="/graph">Graphs</Link>
</div>
</BrowserRouter>
);
}
}
export default SideNavComponent;
Router.js
import React from 'react';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import HomeComponent from './pages/HomeComponent';
import DeviceComponent from './pages/DeviceComponent';
import TransformationComponent from './pages/TransformationComponent';
import GraphComponent from './pages/GraphComponent';
const Router = () => {
return (
<BrowserRouter>
<div>
<Switch>
<Route path="/device" component={DeviceComponent} />
<Route path="/transform" component={TransformationComponent} />
<Route path="/graph" component={GraphComponent} />
<Route exact path="/" component={HomeComponent} />
</Switch>
</div>
</BrowserRouter>
);
};
export default Router;
The problem is you have multiple instances of browser router and history is getting confused. You can fix this by re-organising the structure of application like the below example.
// *-----------------------*
// | MAIN-APP COMPONENT |
// *-----------------------*
import React, { Component } from "react";
import { Col, Well, Panel } from "react-bootstrap";
import { Route, Switch } from "react-router-dom";
import SideNavComponent from "./SideNavComponent";
const HomeComponent = () => <div>Home</div>;
const GraphComponent = () => <div>Graph</div>;
const DeviceComponent = () => <div>Device</div>;
const TransformationComponent = () => <div>Transformation</div>;
class App extends Component {
render() {
return (
<div>
<div className="header" />
<div className="body">
<Col md={3}>
<Well>
<SideNavComponent />
</Well>
</Col>
<Col md={9}>
<Panel>
<Switch>
<Route path="/device" component={DeviceComponent} />
<Route path="/transform" component={TransformationComponent} />
<Route path="/graph" component={GraphComponent} />
<Route exact path="/" component={HomeComponent} />
</Switch>
</Panel>
</Col>
</div>
<div className="footer" />
</div>
);
}
}
export default App;
// *-----------------------*
// | SIDENAV-COMPONENT |
// *-----------------------*
import React, { Component } from "react";
import { Nav, NavItem } from "react-bootstrap";
import { Link } from "react-router-dom";
class SideNavComponent extends Component {
render() {
return (
<div style={{ flexDirection: "column" }}>
<Link to="/">Home</Link>
<Link to="/graph">Graphs</Link>
</div>
);
}
}
export default SideNavComponent;
// *-----------------------*
// | MAIN.JS (ENTRY POINT) |
// *-----------------------*
import React from 'react'
import { render } from 'react-dom'
import App from './components/App';
import { BrowserRouter } from 'react-router-dom';
render((
<BrowserRouter>
<App />
</BrowserRouter>
), document.getElementById('root'));

componentWillEnter not being called with TransitionGroup

I'm trying to add page transitions to my app with react router 4. For some reason the functions componentWillEnter, componentWillLeave are not being called. Does someone has any idea why?
index.js
import React from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router } from 'react-router-dom';
import App from './containers/App';
render(
<Router>
<App />
</Router>,
document.getElementById('root')
);
components/App.js:
import React, { Component } from 'react';
import { Route, Link } from 'react-router-dom';
import TransitionGroup from 'react-transition-group/TransitionGroup';
import Home from '../components/home/Home';
import Users from '../components/users/Users';
const firstChild = (props) => {
const childrenArray = React.Children.toArray(props.children);
return childrenArray[0] || null;
};
class App extends Component {
render() {
return (
<div className="App">
<ul className="TopBar">
<Link to="/">Home</Link>
<Link to="/users">Users</Link>
</ul>
<Route
exact
path="/"
children={({ match, ...rest }) => (
<TransitionGroup component={firstChild}>
{match && <Home {...rest} />}
</TransitionGroup>
)} />
<Route
path="/users"
children={({ match, ...rest }) => (
<TransitionGroup component={firstChild}>
{match && <Users {...rest} />}
</TransitionGroup>
)} />
</div>
);
}
}
export default App;
components/AnimatedWrapper.js
import React, { Component } from 'react';
const AnimatedWrapper = WrappedComponent => class AnimatedWrapper extends Component {
constructor(props) {
super(props);
this.state = {
animate: 0
};
}
componentWillAppear(cb) {
console.log('WillAppear');
this.setState({
animate: 1
});
cb();
}
componentWillEnter(cb) {
console.log('WillEnter');
this.setState({
animate: 1
});
cb();
}
componentWillLeave(cb) {
console.log('WillLeave');
this.setState({
animate: 0
});
setTimeout(() => cb(), 175);
}
render() {
console.log(this.state.animate);
const style = {
opacity: `${this.state.animate}`,
};
return (
<div style={style} className="animated-page-wrapper">
<WrappedComponent {...this.props} />
</div>
);
}
};
export default AnimatedWrapper;
components/Home.js
import React, { Component } from 'react';
import AnimatedWrapper from '../animated/AnimatedWrapper';
class HomeComponent extends Component {
render() {
return (
<div className="page">
<h1>Home</h1>
<p>Hello from the home page!</p>
</div>
);
}
}
const Home = AnimatedWrapper(HomeComponent);
export default Home;
components/Users.js:
import React, { Component } from 'react';
import AnimatedWrapper from '../animated/AnimatedWrapper';
class UsersComponent extends Component {
render() {
return (
<div className="page">
<h1>Users</h1>
<p>Hello from users page!</p>
</div>
);
}
}
const Users = AnimatedWrapper(UsersComponent);
export default Users;
EDIT: I think TransitionGroup cannot work this way. It's low level component and it cannot reach the componentWillEnter() hook inside the <Switch> and <Route>.
You can use ReactCSSTransitionGroup instead.
Or try something more complicaded like this: https://hackernoon.com/animated-page-transitions-with-react-router-4-reacttransitiongroup-and-animated-1ca17bd97a1a

Resources