I have a file route.js which has
import React from 'react'
import { render } from 'react-dom'
import {HashRouter ,Route,Link} from 'react-router-dom'
const Router = (props) => (
<HashRouter>
<div>
<Route exact path="/" render={() => <list data={props.data}/>}/>
<Route path="/list" render={() => <Table data={props.data}/>}/>
</div>
</HashRouter>
here is the edit page code-
import React, { Component} from 'react'
export default class Edit extends Component {
render() {
return (
<div>
<center>{this.props.data}</center>
</div>
);
}
}
i want to pass the list data to the next page.how can i pass props to page from router
If you want to pass any props to some route you can just pass it through the params prop of Link.
Here in your case you could just set a button anywhere on the FreindList page which should be like:
<Link to='edit' params={{data: props.data.name}}>
<button>Edit</button>
</Link>
Further you can access this array in the edit page aswel.
don not forget to import Link from react router
Since you are using react-router-dom which is react router 4, you can just use, something like this:
<Link to={{
pathname: '/edit',
state: { data: props.data.name }
}}>
<button>Edit</button>
</Link>
You will get it in this.props.location.state in the edit component.
For more documentation on react router 4 check this out
Related
I am new to react and react-router, so please go easy on me.
I am trying to implement router in my Todo List project, where path="/" takes me to my todo list and path="/id" takes me to a test page (later will show the description of the task).
When I click the link that takes me to "/id", the URL in the browser changes but the page/content doesn't. However, when I refresh my browser, the test page loads.
I have put the Switch in App.js shown below.
import React, { Component } from "react";
import "./App.css";
import TodoList from "./components/TodoList";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Test from "./components/Test";
class App extends Component {
render() {
return (
<Router>
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route exact path="/" component={TodoList} />
<Route path={`/id`} component={Test} />
</Switch>
</div>
</Router>
);
}
}
export default App;
And I have put the Link to "/id" as shown below in a child component of component which is called here in App.js.
<div key={todo.id}>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
</div>
Am I missing something which is causing my component to not load when I click the link?
Edit: Here's a link to my project. https://stackblitz.com/edit/react-7cpjp9?file=src/index.js
Issue
Ok, the issue is exactly as I had suspected. You are rendering multiple routers in your app. The first is a BrowserRouter in your index.js file, the second, another BrowserRouter in App.js, and at least a third BrowserRouter in Todo.js. You need only one router to provide a routing context for the entire app.
The issue here is that the router in Todo component is the closest router context to the links to specific todo details. When a link in Todo is clicked, this closest router handles the navigation request and updates the URL in the address bar. The blocks, or "masks", the router in App component or index.js that is rendering the routes from "seeing" that a navigation action occurred. In other words, the URL in the address bar is updated by the inner router, but the outer router doesn't know to render a different route.
Solution
Keep the BrowserRouter wrapping App in index.js and remove all other routers used in your app.
App - Remove the Router component. Also, reorder the routes/paths from most specific to least specific so you don't need to specify the exact prop on every route. Allows more specific paths to be matched and rendered before less specific paths by the Switch component.
class App extends Component {
render() {
return (
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route path="/id/:todoId" component={Test} />
<Route path="/" component={TodoList} />
</Switch>
</div>
);
}
}
Todo - Remove the Router component. Move the key={todo.id} up to the outer-most element so when todos array is updated React can reconcile updates.
class Todo extends Component {
constructor(props) {
super(props);
this.state = {
id: null,
value: "",
details: "",
};
this.submitUpdate = this.submitUpdate.bind(this);
}
submitUpdate(value) {
const { updateTodo } = this.props;
updateTodo(this.state.id, value);
this.setState({
id: null,
value: "",
});
}
render() {
const { todos, completeTodo, removeTodo } = this.props;
if (this.state.id) {
return <TodoForm edit={this.state} onSubmit={this.submitUpdate} />;
}
return todos.map((todo, index) => (
<div
className={todo.isComplete ? "todo-row complete" : "todo-row"}
key={todo.id}
>
<div>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
</div>
<div className="icons">
<RiCloseCircleLine
onClick={() => removeTodo(todo.id)}
className="delete-icon"
/>
<TiEdit
onClick={() => this.setState({ id: todo.id, value: todo.text })}
className="edit-icon"
/>
<RiCheckboxCircleLine
onClick={() => completeTodo(todo.id)}
className="delete-icon"
/>
</div>
</div>
));
}
}
First of all the approach, you are taking for dynamic routing is wrong.
It should be like this you will have to add the exact keyword on the dynamic route.
<Route exact path="/id/:todoId" component={Test} />
And
<div key={todo.id}>
<Link className="todo-text" to={`/id/${todo.id}`}>
{todo.text}
</Link>
import React, { Component } from "react";
import "./App.css";
import TodoList from "./components/TodoList";
import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";
import Test from "./components/Test";
class App extends Component {
render() {
return (
<Router>
<div className="todo-app">
<p>
<Link to="/">Home</Link>
</p>
<Switch>
<Route exact path="/" component={TodoList} />
**<Route exact path={`/id`} component={Test} />**
</Switch>
</div>
</Router>
);
}
}
export default App;
i am having trouble with reach router nested routes, I am trying to navigate to / and render page2, but I am stuck on "/" homepage the same page when the route changes to //
<Appjs>
import React from "react";
import "./App.css";
import Homepage from "./Components/Homepage";
import Details from "./Components/Details";
function App() {
return (
<div>
<Router>
<Homepage path="/">
<Details path="details" />
</Homepage>
</Router>
</div>
);
}
export default App;
import React, { Component, useEffect, useState } from "react";
import styled, { isStyledComponent } from "styled-components";
import NavLink from "./NavLink";
import { Link } from "#reach/router";
const Homepage = () => {
const [users, setUsers] = useState([]);
return (
<React.Fragment>
<div className={"container"}>
<Styleddiv>
<h2>Select an Account</h2>
<div style={{ padding: 0 }}>
{Object.values(users).map((item) => (
<Link to={`details/${item.name}`}>
<img src={item.profilepicture} alt="Girl in a jacket"></img>
<span>{item.name}</span>
</Link>
))}
</div>
</Styleddiv>
</div>
</React.Fragment>
);
};
export default Homepage;
Am I missing something while structuring the routes inside the router, Kindly help me
So in Homepage If i click on any Link the route changes to /details but the details page fails to render
https://codesandbox.io/s/billowing-hill-j5gmy?file=/src/Homepage.js
Did you miss your Router import on your App.js file?
import React from "react";
import { Router, Link } from "#reach/router";
import Homepage from "./Homepage";
import Details from "./Details";
export default function App() {
return (
<div>
<nav>
<Link to="/">Home</Link>
<Link to="dashboard">Detail</Link>
</nav>
<Router>
<Homepage path="/" />
<Details path="dashboard" />
</Router>
</div>
);
}
Edit: Code Sand Box
This is how I use nested routes
Code sandbox
In order to nest routes you need to place them in the child component of the route.
The render prop is used instead of component because it stops the inline functional component from being remounted every render, see explanation.
The match object contains the information about how a route matched the URL, so we can have a nested route using the url property which gives us the matched portion of the URL, see explanation.
I am building a consumer facing app with a admin dashboard. I want to keep the routing separate for them and so trying to delegate :-
App.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
//styles
import './style/bootstrap/bootstrap.scss';
//apps
import Mainapp from './mainapp/Mainapp';
import Admin from './admin/Admin';
const MainappContainer = () => (
<Mainapp />
);
const AdminContainer = () => (
<Admin />
);
class App extends Component{
render(){
return (
<Router>
<Switch>
<Route path="/admin" component={AdminContainer}/>
<Route path="/" component={MainappContainer}/>
</Switch>
</Router>
)
}
}
export default App;
Admin.js
import React, {Component} from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
//styles
import './admin-style.scss';
//layout
import ControlPanel from './component/layout/ControlPanel';
import Navbar from './component/layout/Navbar';
//pages
import Quote from './component/pages/quote/Quote';
class Admin extends Component{
render(){
return (
<div className="adminWrapper">
<ControlPanel />
<section className="viewPanel">
<Navbar />
<Router>
<Route path="/quote" component={Quote}/>
</Router>
</section>
</div>
)
}
}
export default Admin;
However when I hit the URL
http://localhost:3000/admin/quote
it doesn't seem to load the quote component
Quote.js
import React, { Component } from 'react';
class Quote extends Component {
render() {
return (
<div className="float-right pr-3">
<h3>
Quote Page
</h3>
</div>
)
}
}
export default Quote;
When dealing with nested subroutes, the easiest solution is to use match.
path - (string) The path pattern used to match. Useful for building nested
Routes.
url - (string) The matched portion of the URL. Useful for building
nested Links.
By design, components placed inside a Route's component render method are given several additional props from react-router-dom. Among them are history and match. You can leverage these props to either to match against sub routes and/or to control browser history location.
In addition, you only need one instance of BrowserRouter sitting at the top-level of the application, then you can use Switch to optionally render any main or sub routes. And you don't need to use class components unless you're utilizing state and/or a class field.
A very basic, rudimentary working example of your application:
src/components/Admin/index.js
import React from "react";
import { Switch, Link, Route } from "react-router-dom";
import ControlPanel from "../ControlPanel";
import Quote from "../Quote";
// since Admin is placed inside a Route's component render
// method, it has access to history and match
function Admin({ history, match }) {
return (
<div className="adminWrapper">
<ControlPanel />
<section className="viewPanel">
<Link to={`${match.url}/quote`}>View quote</Link>
<br />
<Switch>
<Route exact path={`${match.path}/quote`} component={Quote} />
</Switch>
</section>
<br />
<button type="button" onClick={() => history.goBack()}>
Go Back
</button>
</div>
);
}
export default Admin;
index.js
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter, Link, Route, Switch } from "react-router-dom";
import Admin from "./components/Admin";
const linkStyle = {
padding: "0 10px"
};
function App() {
return (
<BrowserRouter>
<Link style={linkStyle} to="/">
Home
</Link>
<Link style={linkStyle} to="/admin">
Admin
</Link>
<Switch>
<Route path="/admin" component={Admin} />
<Route path="/" render={() => <h1>Main App</h1>} />
</Switch>
</BrowserRouter>
);
}
ReactDOM.render(<App />, document.getElementById("root"));
Follow the Nested Routing Example
The main changes you need to do are:
1. Remove the <Router></Router> from Admin component and
2. Prepend match.path to "/quotes", like it is done in Topics component in the example. In the example, Topics is a function component so it is receiving match as function parameter. As your Admin component is class component, you can access it as this.props.match in render method.
<Route path={`${this.props.match.path}/quote`} component={Quote}/>
<Route exact path="/admin" component={AdminContainer}/>
<Route exact path="/admin/quote" component={Quote}/>
This won't route you to /admin/quote instead it will route you to /admin/admin/quote.
Since it is inside admin just /quote is enough
<Route path="/admin" component={AdminContainer}/>
<Route path="/quote" component={Quote}/>
id like to change my header color when in my contact page. unable to get location from react router. I get "TypeError: Cannot read property 'pathname' of undefined".
I know I'm missing something simple but i cant seem to figure it out.
import React from 'react';
import './Header.css';
import { NavLink } from 'react-router-dom';
class Header extends React.Component {
render() {
const blackHeader = {"background-color" : 'black'}
const clearHeader = {"background-color" : 'transparent'}
return(
<header style={ this.props.location.pathname === '/Contact' ? { blackHeader } : { clearHeader } }>
<NavLink to={'/'}><h2>Name</h2></NavLink>
<nav>
<ul>
<li><NavLink to={'/'}>Portfolio</NavLink></li>
<li><NavLink to={'Contact'}>Contact</NavLink></li>
<li>Blog</li>
</ul>
</nav>
</header>
)
}
}
export default Header;
You need to pass the location props to your Header component or you can use the HOC withRouter in react-router-dom.
import { NavLink, withRouter } from 'react-router-dom';
export default withRouter(Header)
Edit for clarity:
If you render a component in your router in a Route component:
<Route path='/' component={Home} />
This will give that component (Home in this case) access to the location props which can then be passed to children of that component.
import React, { Component } from 'react'
import OtherComponent from './OtherComponent'
class Home extends Component {
render() {
return (
<div>
<OtherComponent locations={this.props.locations}
</div>
)
}
}
export default Home;
However, if the component is not passed through Route it will not have access to location props. For example, if you put your header outside of your routes, something like:
<Router>
<Header/>
<Switch>
<Route path='/' component={Home}/>
</Switch>
</Router>
It will not have location props.
I'm not sure how your component tree is set up but, I hope this gives a little clarity to how the location props are accessed and used in your app.
The documentation is a good place to get some more clarity on the workings of react router as well https://reacttraining.com/react-router/core/api/Route/route-props
Yea, I can see in the contact path
<li><NavLink to={'Contact'}>Contact</NavLink></li> ,
it should be something like
<li><NavLink to='/Contact'>Contact</NavLink></li>.
You have to include the back slash, I mean this ' / ' before the pathname. So try it now.
i'm trying to use react router in my reactjs app. And I encountered this problem:
This is what i'm trying to do:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import About from '../Pages/About';
import Home from '../Pages/Home';
import Topics from '../Pages/Topics';
import LinkTest from '../Pages/LinkTest';
class AppRouter extends Component {
render() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/home">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
<Route path="/home" component={LinkTest}/>
</ul>
<hr />
<Route path="/home" component={Home}/>
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
}
}
export default AppRouter;
Ignore "about" and "topic" component, when I click on "Home" link, it should target 2 routes, one will render "LinkTest" and the other renders "Home".
This is what inside "LinkTest":
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
class LinkTest extends Component {
render() {
const {match}=this.props;
return (
<div>
<Link to={`${match.url}/Test`}>Link To Test</Link>
</div>
);
}
}
export default LinkTest;
And inside my "Home" component:
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import Test from './Test';
class Home extends Component {
render() {
const {match} = this.props;
console.log(match.url);
return (
<Router>
<div>
<h2>
Hello from Home page
<Link to={`${match.url}/Test`}>Link To Test</Link>
<Route path={`${match.url}/Test`} component={Test}/>
</h2>
</div>
</Router>
);
}
}
export default Home;
However:
When i click on the link inside "LinkTest" component (which was rendered earlier), the url on the browser is shown "http://localhost:3000/home/Test", but nothing happens.
When i clicked on the link inside "Home" component, (which was rendered the same time as the "LinkTest" using the same link), it showed the same url on the browser: "http://localhost:3000/home/Test", only this time it rendered the "Test" component.
Why does this happen? (what i want to achieve is I want to use the link inside "LinkTest" to render "Test" component inside "Home" component, or something similar).
I hope this is clear enough.
You can do it in following way:
<Route exact path='/a' component={A} />
<Route path='/b' component={B} />
// Following should be router inside Component B
<Route exact path='/b/abc' component={OtherComponent}
If you want I've prepared few react-router 4 examples. These are hosted here. https://github.com/SandipNirmal/react-router-examples
If you need Nested routing inside ComponentB you should add Links for those Routes as well. And use match.url and match.path to build the nested Links and Routes.
const ComponentB = ({ match }) => {
return (
<div>
<div>
<ul>
<li><Link to={`${match.url}/c`}>Component C</Link></li>
// more Links
<li><Link to={`${match.url}/css`}>CSS</Link></li>
<li><Link to={`${match.url}/react`}>React</Link></li>
</ul>
</div>
<div>
<Route path={`${match.path}/c`} component={ComponentC} />
// more nested Routes
<Route path={`${match.path}/css`} render={() => { return <h1>CSS</h1> }}/>
<Route path={`${match.path}/react`} render={() => { return <h1>React</h1> }}/>
</div>
</div>
);
}
Nested routing
Components created via Route will automatically be passed the following prop objects: match, location and history.
Using match you can implement nested Routes. The match object contains the following properties:
params — (object) Key/value pairs parsed from the URL corresponding
to the dynamic segments of the path
isExact — (boolean) true if the entire URL was matched (no trailing characters)
path — (string) The path pattern used to match. Useful for building nested Routes
url — (string) The matched portion of the URL. Useful for building
nested Links
Reference
https://medium.freecodecamp.org/beginners-guide-to-react-router-4-8959ceb3ad58
https://medium.com/#pshrmn/a-simple-react-router-v4-tutorial-7f23ff27adf