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;
Related
i have routing attribure in my react.js app. when i click on the route for the first time it works fine but if i refresh in the page it gives error saying cannot read property ... of null. I'm making api call from tmdb. Why i get error on refresh? Secondly, i have another route which i cannot access to it unless it is above the first route i mention. I mean when i put TvInfo above the MovieInfo tvinfo works movie info doesn't. This way only movieinfo works. If i click the above route elements first then clicking tvinfo element i get the previous clicked movie on the screen again. What could be the problem i tried many things? thanks
import React,{ Component } from 'react';
import Home from './components/Home';
import MovieInfo from './components/MovieInfo';
import TvInfo from './components/TvInfo';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
class App extends Component {
render(){
return(
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/:movie_id" component={MovieInfo} />
<Route path="/:tv_id" component={TvInfo} />
</Switch>
</BrowserRouter>
)
}
}
export default App;
You need to design your Routes a little differently, Route component cannot differentiate between two separate params.
class App extends Component {
render(){
return(
<BrowserRouter>
<Switch>
<Route exact path="/" component={Home} />
<Route path="movie/:movie_id" component={MovieInfo} />
<Route path="tv/:tv_id" component={TvInfo} />
</Switch>
</BrowserRouter>
)
}
}
export default App;
this is my movieInfo component
class MovieInfo extends React.Component{
render(){
return(
<div>
<p style={{marginLeft:'47%',fontSize:25}}>{this.props.selectedMovie.original_title}</p>
<img style={{marginLeft: '20%'}}
src={`http://image.tmdb.org/t/p/w780${this.props.selectedMovie.backdrop_path}`} alt="moviebackdrop"/>
<div style={{float:'right',marginRight:45}}>
<p>Release Date: {this.props.selectedMovie.release_date}</p>
<p>Vote: {this.props.selectedMovie.vote_average}<Icon name="star" color="yellow" /></p>
</div>
<p style={{width:800,marginLeft: '20%'}} >{this.props.selectedMovie.overview}</p>
<p>{this.props.data.homepage}</p>
</div>
)}
}
const mapStateToProps = (state) => {
return{
selectedMovie:state.movie.selectedMovie,
}
}
to be able to display this screen i have another component where you show the images for the movies. when i click on the image it renders movieInfo component.
here is my image component.
selectMovie = () => {
this.props.setMovie(this.props.movie)
}
render(){
return(
<Link to={"movie/" + this.props.movie.id}>
<div onClick={() => this.selectMovie()}>
<div className="item">
<img className="img"
src={`http://image.tmdb.org/t/p/w342${this.props.movie.backdrop_path}`} alt="moviebackdrop"/>
<p className="title">{this.props.movie.original_title}</p>
<p className="overview">{this.props.movie.overview}</p>
</div>
</div>
</Link>
)}
}
I am trying to navigate to a login page using react router but when the button is clicked, the next page is displayed on the same page without actually navigating to the next page.
Here is my code
import React, { Component } from 'react';
import { BrowserRouter as Router, Route, Switch, Link } from 'react-router-dom';
import $ from 'jquery';
import { Login } from './Login';
export class Index extends Component {
render() {
return (
<div>
<div align='center'>
<h3> Project Management System </h3>
</div>
<p>
Here, you can search for the previous B.sc, M.sc and Ph.D projects that have been carried out in the department. <br/><br/>
</p>
<Router>
<div>
<Link to="/login">Continue </Link>
<Route exact path={"/login"} component={Login}/>
</div>
</Router>
</div>
);
}
}
When I click on continue button, it's supposed to show the login page alone, without showing the previous page, but here, it shows both previous page and the login page.
--Edit--
Move your button and info in another Component, call it Home or something similar.
Home.js
import React from "react"
import { Link } from "react-router-dom"
const Home = () => {
return(
<div>
<div style={{textAlign: "center"}}>
<p>Your paragraph</p>
<Link to="/login">Continue </Link>
</div>
</div>
)
}
export default Home
Index.js
now you'll have a cleaner Router
keep all your imports and bring in the Home component
export class Index extends Component {
render() {
return (
<div>
<Router>
<div>
<Switch>
<Route path="/" exact={true} component={Home}>
<Route path="/login" component={Login}/>
</Switch>
</div>
</Router>
</div>
The reason for that behavior is very simple. You wrapped only Login component with the router. You have to create routes with the Switch component to change the views. Here is an example https://codesandbox.io/s/2xqxqpo550
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
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>
</>
);
};
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