React Router- Link not directing properly - javascript

I have the following component...
import React from 'react';
import { Router, Route, Link, browserHistory, IndexRoute } from 'react-router'
class Bottom extends React.Component {
constructor(){
super();
this.state = {link:"Don't have an account?"}
}
render(){
return (
<div>
<div className="sub-login">
<p>{this.state.link}<Link to="/register"> Register here</Link></p>
</div>
</div>
);
}
}
export default Bottom;
As you can see I have a <Link> pointing to the page I want the user to go to if it is clicked.
This component is then bundled into another class called <Register />.
And then I have the following Routes...
class App extends React.Component {
render(){
return (
<Router history={hashHistory}>
<Route path='/' component={Index} >
<IndexRoute component={Register} />
<Route path='/register' component={Register} />
</Route>
</Router>
);
}
}
When the Link is clicked, the url changes to /register, but the content of the page is still that of the home page, which is <Index /> component.
Why won't it show the <Register /> component? What must I change to render the register component when the link is clicked?

I realized that all I had to do was add {this.props.children} to my Index Layout. So when the Link is clicked, the Register Layout will be loaded into my Index Layout.
The following code made it work...
render(){
return (
<div>
{this.props.children} <-----
<div className="sub-login">
<p>{this.state.link}<Link to="/register"> Register here</Link></p>
</div>
</div>
);

Related

React Router - Why is the switch not changing html when the path changes?

I am working on a web app, and i am having some issues with reactJS Router. When i redirect to the /sell path the HTML form the / path stays, and the HTML inside the /sell route doesn't load.
Am i doing something wrong? would anyone be able to point me towards the right direction?
import React, { Component } from "react";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Helmet from "react-helmet";
import CreateList from "./CreateList";
//https://colorhunt.co/palette/33990
//https://colorhunt.co/palette/66990
class Home extends Component {
constructor(props) {
super(props);
this.state = { appTitle: "better craigslist"};
}
render() {
return (
<React.Fragment>
<Helmet>
<title>{this.state.appTitle}</title>
</Helmet>
<Router>
<Switch>
<Route path="/">
<div id="header-text">
<h1 className="center-align">
<b>Sellify</b>
</h1>
<h5 className="center-align">
Need to get rid of your stuff? create a listing and sell it here! <br /> Looking for something? Check if its on selify!
</h5>
</div>
<div className="col s12 center">
<Router>
<Link to="/sell">
<button className="btn" id="create-listing-button">
Create Listing
</button>
</Link>
</Router>
</div>
</Route>
<Route path="/sell">
<h1>Test</h1>
</Route>
</Switch>
</Router>
</React.Fragment>
);
}
}
export default Home;
Thank you very much!
Issue
You've more than one Router. The inner Router context is handling the links so the outer Router isn't notified.
Solution
Use only one Router component, remove the Router around the Link. Additionally, when using a Switch, path order and specificity matter. You want to oder your more specific paths before less specific paths. "/" is a path prefix for all paths and would be matched and rendered before "/sell".
class Home extends Component {
constructor(props) {
super(props);
this.state = { appTitle: "better craigslist" };
}
render() {
return (
<React.Fragment>
<Helmet>
<title>{this.state.appTitle}</title>
</Helmet>
<Router>
<Switch>
<Route path="/sell">
<h1>Test</h1>
</Route>
<Route path="/">
...
<div className="col s12 center">
<Link to="/sell">
<button className="btn" id="create-listing-button">
Create Listing
</button>
</Link>
</div>
</Route>
</Switch>
</Router>
</React.Fragment>
);
}
}

React Router is leaving my main page loaded when trying to load other pages

I have a MainPage that is loaded in App.js but when I use Browser Router and Route it will keep the MainPage and loads the second page over the top of it. Any tips would be helpful.
class App extends Component {
render() {
return(
<BrowserRouter>
<div className="App">
<Mainpage></Mainpage>
</div>
</BrowserRouter>
);
}
}
export default App;
The other thing that is weird is that it is loading the background of the page and styling that it is routing to when the button is not even pushed.
This is the main page.
class Mainpage extends Component {
render() {
return (
<div>
<header>
<nav>
<ul>
<li>
<Link exact to="/meettheteam">
This is a new Page
</Link>
</li>
</ul>
</nav>
</header>
<h1>
THE
<br />
BARBER
<br />
SHOP
</h1>
<p>
<img src={logo} alt="logo" />
<img src={facebookLogo} alt="logoFacebook" />
<img src={twitterLogo} alt="logoTwitter" />
#TheBarberShop
</p>
<ul>
<div className="schedule">
<li>SCHEDULE</li>
</div>
<div className="styles">
<li>STYLES</li>
</div>
<div className="meettheteam">
<li>MEET THE TEAM</li>
</div>
</ul>
<Switch>
<Route exact path="/meettheteam" component={MeetTheTeam} />
</Switch>
{/* <Route path="/stylesandprices" component={StylesAndPrices}/> */}
</div>
);
}
}
export default Mainpage;
Assuming you want the navigation portion of your main page to always render (to obviously allow navigation) then I have the following suggestions:
Move the header/nav to App component and render at the top of the router.
Move the Switch also to App and render your Mainpage and other page components in their own respective Route components, in decreasing specificity, i.e. "/pathA/b" listed before "/pathA".
Since the Switch matches and returns the first matching Route or Redirect, render the Mainpage route last as a default "home page".
If you want link highlighting (i.e. noticed the exact prop on the Link) then use NavLink as the Link component doesn't take this prop. Though, the exact prop here really only matters if you have nested routes that you don't want the link to appear active for
Changes
App
class App extends Component {
render() {
return (
<BrowserRouter>
<div className="App">
<header>
<nav>
<ul>
<li>
<Link to="/meettheteam">
This is a new Page
</Link>
</li>
</ul>
</nav>
</header>
<Switch>
<Route path="/meettheteam" component={MeetTheTeam} />
<Route path="/stylesandprices" component={StylesAndPrices} />
{/* other routes listing in decreasing specificity */}
<Route component={Mainpage} />
</Switch>
</div>
</BrowserRouter>
);
}
}
Mainpage
class Mainpage extends Component {
render() {
return (
<div>
<h1>
THE
<br />
BARBER
<br />
SHOP
</h1>
<p>
<img src={logo} alt="logo" />
<img src={facebookLogo} alt="logoFacebook" />
<img src={twitterLogo} alt="logoTwitter" />
#TheBarberShop
</p>
<ul>
<div className="schedule">
<li>SCHEDULE</li>
</div>
<div className="styles">
<li>STYLES</li>
</div>
<div className="meettheteam">
<li>MEET THE TEAM</li>
</div>
</ul>
</div>
);
}
}
Routes should be wrapped inside of a <Switch> component of react-router-dom
Right usage:
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import ComponentA from './componenta'
import ComponentB from './componentb'
function App() {
return (
<Router>
<Switch>
<Route path="/">
<ComponentA />
</Route>
<Route path="/componentb">
<ComponentB />
</Route>
</Switch>
</Router>
);
}
export default App
This example below would render first route and second route on top of each other, This is the similar way on how the code snippets of the question was structured. The first route was wrap with Switch while the second route was outside of Switch
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import ComponentA from './componenta'
import ComponentB from './componentb'
function App() {
return (
<Router>
<Switch>
<Route path="/">
<ComponentA />
</Route>
</Switch>
<Route path="/">
<ComponentB />
</Route>
</Router>
);
}
export default App;
Tips/Suggestion:
The best thing to do is to wrap all the Route's with Switch statement at the top level of the app hierarchy

Passing State of App.js to Child Component

I'm working on the main page of a website and I'd like to have a specific nav/menu bar for the main page and a different one for the other components (the main page hides de "home" button and the others show it).
The issue I have at the moment is that the logic of rendering this menu lives on App and I'm having a hard time to find the proper way to pass the state of my App component to the other components, probably just because of the lack of experience.
import React from "react";
import { BrowserRouter, Route, Link } from "react-router-dom";
import Main from "./main";
import MapContainer from "./mapcontainer";
import Venue from "./venue";
import Schedule from "./schedule";
import Accommodation from "./accommodation";
import Couple from "./couple";
import Honeymoon from "./honeymoon";
import Uploader from "./uploader";
import Friday from "./friday";
import Saturday from "./saturday"
import Sunday from "./sunday";
import Dresscode from "./dresscode";
export class App extends React.Component {
constructor(props) {
super(props);
this.state = {
error: false,
isHome: true
};
}
componentDidMount() {
console.log("App mounted");
}
render() {
function HomeComponentMenu(props) {
return (
<nav className="header-on-app">
<button>Contact Us</button>
<button className="logout-btn">Logout</button>
</nav>
);
}
function AllOtherComponentsMenu(props) {
return (
<nav className="header-on-app">
<button><Link to="/">Home</Link></button>
<button>Contact Us</button>
<button className="logout-btn">Logout</button>
</nav>
);
}
const isHome = this.state.isHome;
let menu;
if (isHome) {
menu = <HomeComponentMenu/>;
} else {
menu = <AllOtherComponentsMenu/>;
}
return (
<BrowserRouter>
<nav className="header-on-app">{menu}</nav>
<div className="app-container">
<Route exact path="/" component={Main} />
<Route exact path="/venue" component={Venue}/>
<Route exact path="/venuemap" component={MapContainer}/>
<Route exact path="/schedule" component={Schedule}/>
<Route exact path="/accommodation" component={Accommodation}/>
<Route exact path="/couple" component={Couple}/>
<Route exact path="/honeymoon" component={Honeymoon}/>
<Route exact path="/uploader" component={Uploader} />
<Route exact path="/friday" component={Friday} />
<Route exact path="/saturday" component={Saturday} />
<Route exact path="/sunday" component={Sunday} />
<Route exact path="/dresscode" component={Dresscode} />
</div>
</BrowserRouter>
);
}
}
Component I'd like to set isHome to false
import MapContainer from "./mapcontainer";
export default class Venue extends React.Component {
constructor(props){
super(props);
this.state = {
error:false,
}
}
render() {
return (
<div className="venue-container">
<h1>Anna & Rodolfo</h1>
<h2><span>_______</span> Venue . Local . Veranstalungsort <span>_______</span></h2>
{this.state.error && <h2 className="error">Ops! Something went wrong.</h2>}
<div className="grid-container-venue">
<div className="item">
<img src="venue.png" alt="Avatar" className="image"/>
<div className="background-grid-items">
<div className="text-address">
<a href="https://www.g71972,15z/data=!4887b!8m2!3d52.47094!4d12.71972">
<p>Kulturschloss</p>
<p>Abcd.30 3456 Berlin </p>
<p>Germany . Alemanha . Deutschland</p>
</a>
</div>
</div>
</div>
<div className="item">
<img src="website.png" alt="Avatar" className="image"/>
<div className="background-grid-items">
<div className="text">
<a href="https://www.kult.de/">
<p>To the Website</p>
<p>Para o Website</p>
<p>Zur Website</p>
</a>
</div>
</div>
</div>
<div className="item">
<img src="transportation.png" alt="Avatar" className="image"/>
<div className="background-grid-items">
<div className="text">
<p>Transportation</p>
<p>Traslado</p>
<p>Transport</p>
</div>
</div>
</div>
<div className="item">
<div className="background-grid-venue">
<div className="map">
<MapContainer/>
</div>
</div>
</div>
</div>
</div>
);
}
}
Since my components are being rendered by React Router, I tried to render props passing it in an inline function and afterwards pass along to the argument I was creating, but somehow it didn't work. Would you have any suggestions on how to solve this? Thank you very much!
To pass a state to a child component, you have to pass it as props of the child component.
e.g.
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import TableView from './TableView'
export default class App extends Component {
state = {
item: 'this is the item'
}
render() {
return(
<Router>
<Route exact path="/home">
<TableView itemList={this.state.item}></TableView>
</Route>
</Router>
)
}
}
to get the props in the child component
import React, { Component } from 'react'
export default class TableView extends Component {
render(){
<React.Fragment>
{this.props.item}
</React.Fragment>
}
}
Hope it helps
EDIT:
It would also help to debug if you have the react devtools addons in your browser to check if the values of the state of each component
To pass props to a react route you have to define it in the render function like this:
<Route exact path="/venue" render={(props) => <Venue updateHomeState={this.updateHomeState}/>}/>
To alter the isHome state on the parent, you could define that function on the parent like:
updateHomeState = (newState) => {
this.setState({ isHome: newState })
}
And then call it in componentDidMount() of your child component like this.props.updateHomeState(newState).

React-router v4 updates url but doesn't render component

I'm using react-router v4, no redux. The code example is below:
class MainPage extends Component {
render() {
return (
<div className="MainPage">
<BrowserRouter>
<Switch>
{/* <Route exact path='/' /> */}
<Route path='/signin' component={SignIn}/>
<Route path='/signup' component={SignUp} />
<Redirect from='*' to='/' />
</Switch>
</BrowserRouter>
</div>
);
}
}
When I'm using Link it updates URL in browser but doesn't render anything, nothing happens. When I resfresh, everything becomes fine and component renderes;
export default class Navbar extends Component {
render() {
return (
<div className="navbar">
<BrowserRouter>
<div>
<Link to='/signin'>Sign in</Link>
<Link to='/signup'>Sign up</Link>
</div>
</BrowserRouter>
</div>
);
}
}
I already tried everything, even withRouter(Component), but it says that with router may only be used inside
How can I deal with this?
Here is the working code. As others explained you should use one BrowserRouter. If you want to render your Navbar component all the time then you should place it above Switch but under BrowserRouter hence you need Link there.
const Navbar = () => (
<div className="navbar">
<Link to='/signin'>Sign in</Link>
<Link to='/signup'>Sign up</Link>
</div>
);
class MainPage extends React.Component {
render() {
return (
<div className="MainPage">
<BrowserRouter>
<div>
<Navbar />
<Switch>
{/* <Route exact path='/' /> */}
<Route path='/signin' component={SignIn} />
<Route path='/signup' component={SignUp} />
<Redirect from='*' to='/' />
</Switch>
</div>
</BrowserRouter>
</div>
);
}
}
You should only have a single BrowserRouter component in your tree. The BrowserRouter component holds the shared state the router used to synchronize the URL with the rendered routes. In your situation, you are getting two different versions of router state because you rendering two BrowserRouter components so you should probably render a single BrowserRouter component somewhere higher in your component tree.
If you have an App component that renders both Navbar and MainPage then you can move the router into that component:
export default class App extends Component {
render() {
return (
<BrowserRouter>
<div className="AppContainer">
<Navbar />
<MainPage />
</div>
</BrowserRouter>
);
}
}

react-router: Cannot read property 'push' of undefined

i'm struggling with react router.
all i want is to build a side menu with a link to login that will show the Login comp in the right pane.
so this is the HTML:
<main id="buschat-app"></main>
<div id="menu"></div>
This is how i render the Buschat main comp and the Router comp.
class Buschat extends React.Component {
constructor() {
super()
}
render() {
return (
<div className="container-fluid">
<div className="row">
<div className="col-sm-2">
<Menu />
</div>
<div className="col-sm-10">
<Main />
</div>
</div>
</div>
)
}
}
ReactDOM.render(<Buschat />, document.getElementById('buschat-app'))
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={Default}/>
<Route path="login" component={Login}/>
</Router>
), document.getElementById('menu'));
now, in i have the Menu comp that looks like that:
import React from 'react';
import { Link } from 'react-router'
export default class Menu extends React.Component {
render() {
return (
<div>
<nav className="navbar navbar-light bg-faded">
<Link to="/">Default</Link>
<Link to="/login">Login</Link>
</nav>
</div>
)
}
}
when the page is load i see the 2 links on the right.
when i click on the login link, i get this console error:
Uncaught TypeError: Cannot read property 'push' of undefined
what im doing wrong? how react-router knows to render login comp on the right pane?
sorry but im new to this...
You are missing context reference in React Component.
static contextTypes = {router: PropTypes.object.isRequired};
Ref: https://github.com/ReactTraining/react-router/issues/3024
Remove
ReactDOM.render(<Buschat />, document.getElementById('buschat-app'))
and change to
ReactDOM.render((
<Router history={hashHistory}>
<Route path="/" component={Buschat}/>
<Route path="login" component={Login}/>
</Router>
), document.getElementById('buschat-app'));
in Buschat class, add the <Menu> component.
I hope this helps!

Categories

Resources