I have this code I have been trying to get to work. Cannot figure out whats wrong with it! There are no errors and I have tried several ways of importing/exporting, and changing the functions to const.
import React, { Component } from "react";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import { Home } from "./Home";
import { Contact } from "./Contact";
class App extends Component {
render() {
return (
<React.Fragment>
<Router>
<Switch>
<Route path="/" component={Home} />
<Route path="/contact">
<Contact />
</Route>
</Switch>
</Router>
</React.Fragment>
);
}
}
export default App;
Then I have two separate functions
import React from "react";
export function Home() {
return (
<div>
<h2>Whats up!</h2>
<p>This is sample text. </p>
</div>
);
}
import React from "react";
export function Contact() {
return (
<div>
<h2>Contact page!</h2>
<p>This is different text. </p>
</div>
);
}
export default Contact;
Based on your last comment - "The above code actually displays whatever is in the first Route no matter the url", the issue is that you're not providing the Route components with an exact prop of true.
Switch will render the first matching Route and skip all the other ones. Since / "matches" all routes, you're only seeing the Home component.
Related
I want to open FormStatus in a new page when I click a button in Form page.
Below is my code.
App.js:
import Form from "./components/Form";
import FormStatus from "./components/FormStatus";
import { BrowserRouter as Router, Route } from "react-router-dom";
function App() {
return (
<Router>
<div className="App">
<Route path="/" component={Form}/>
<Route exact path="/form-status" component={FormStatus}/>
</div>
</Router>
);
}
export default App;
Form.js
import { Link } from "react-router-dom";
const Form = () => {
return (
<div>
<h1>Form Page</h1>
<Link to="/form-status"><button>click</button></Link>
</div>
);
}
export default Form;
FormStatus.js:
import React, {Component} from "react";
class FormStatus extends Component {
render(){
return(
<h1>Form Status Page</h1>
)
}
}
export default FormStatus;
when I click on the button on Form component, my url changes to http://localhost:3000/form-status,
but instead of opening a new page, my FormStatus component comes below Form component.
I want FormStatus to open new a page and only shows contents of my FormStatus component and not contents of Form component
Well, to make this work, you need to change two things in your current code.
Use the Switch from the react-router-dom and wrap your routes within it.
Make your home page (/) route exact instead of the /form-status route, because the /form-status route also includes the leading slash (/). So since both of them will match the expected route it will render them together.
So your code should be something like this in the App.js:
import React from "react";
import Form from "./components/Form";
import FormStatus from "./components/FormStatus";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
export default function App() {
return (
<Router>
<Switch>
<div className="App">
<Route exact path="/" component={Form} />
<Route path="/form-status" component={FormStatus} />
</div>
</Switch>
</Router>
);
}
Working Demo:
After several attempts, I have managed to implement basic nested-routing with React-router-dom.
Here's the simple project structure:
Here are the relevant files:
App.js
import React from "react";
import logo from "./logo.svg";
import "./App.css";
import { BrowserRouter, Switch, Route } from "react-router-dom";
import ParentComponent from "./Components/nestedComponents/ParentComponent";
import NavBar from "./Components/Shared/NavBar";
function App() {
return (
<div className="App">
<BrowserRouter>
<NavBar />
<Switch>
<Route path="/home" name="Home" component={ParentComponent} />
</Switch>
</BrowserRouter>
</div>
);
}
export default App;
NavBar.js
import React from "react";
import { Link } from "react-router-dom";
export default function NavBar() {
return (
<div>
<Link to={`home/nestedComponentOne`}> Nested Component One </Link>
<Link to={`home/nestedComponentTwo`}> Nested Component Two </Link>
</div>
);
}
ParentComponent.js
import React from "react";
import nestedComponentOne from "./nestedComponentOne";
import nestedComponentTwo from "./nestedComponentTwo";
import { Switch, Route } from "react-router-dom";
export default function ParentComponent() {
return (
<div>
<Switch>
<Route path="/home/nestedComponentOne" component={nestedComponentOne} />
<Route path="/home/nestedComponentTwo" component={nestedComponentTwo} />
</Switch>
</div>
);
}
nestedComponentOne.js
import React from "react";
export default function nestedComponentOne() {
return <div>NESTED COMPONENT 1</div>;
}
nestedComponentTwo.js
import React from "react";
export default function nestedComponentTwo() {
return <div>NESTED COMPONENT 2</div>;
}
So here's the Result:
If I click on nestedComponentOne:
If I click on nestedComponentTwo:
The problem is when I click again on nestedComponentOne (or Two) after the I have clicked it the first time, the route gets added to the url string instead of replacing it:
Some update need for your code.
Working Demo
NavBar.js
Here you forget to add slash / at front to link from root.
<Link to={`/home/nestedComponentOne`}> Nested Component One </Link>
<Link to={`/home/nestedComponentTwo`}> Nested Component Two </Link>
ParentComponent.js
As we removed the Switch from this component, so we need to get the matching information from parent router and pass the path to navigate the corresponding your nested component
export default function ParentComponent({ match }) {
return (
<div>
<Route path={`${match.path}/nestedComponentOne`} component={nestedComponentOne} />
<Route path={`${match.path}/nestedComponentTwo`} component={nestedComponentTwo} />
</div>
);
}
Why don't you try putting all the route in one file. Something like this:
<Route exact path="/home" name="Home" component={ParentComponent} />
<Route path="/home/nestedComponentOne" component={nestedComponentOne} />
<Route path="/home/nestedComponentTwo" component={nestedComponentTwo} />
I am connected to an API (The Movie DB) which is returning a list of results (Movies), and when I click into one of the results of the API I need to see a detail page. I have set up dynamic routing, however when I click for the detail page, my URL changes to something like: 'http://localhost:3000/moviedetails/2503', where the 2503 is a unique item ID. However, the DOM is not re-rendering. When I refresh with the same URL, I am then forwarded to the correct page - but I need this to happen upon the click of the link to the details page.
All questions I have seen online have stated that you must use the exact keyword within your routes to fix this, however I am using the exact keyword on all routes except the dynamic one, and still encountering the issue of the DOM not re-rendering.
My App.js file is as follows:
import React from 'react';
import './App.css';
import Home from './components/Home';
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import About from "./components/About.js"
import Discover from './components/Discover';
import Favourites from './components/Favourites';
import Rated from './components/Rated';
import Nav from './components/Nav';
import MovieDetails from './components/MovieDetails'
function App() {
return (
<Router>
<div className="App">
<Nav />
<Switch>
<Route path="/moviedetails/:id" component={MovieDetails}/>
<Route path="/" exact component={Home} />
<Route path="/about" exact component={About} />
<Route path="/discover" exact component={Discover} />
<Route path="/favourites" exact component={Favourites} />
<Route path="/rated" exact component={Rated} />
</Switch>
</div>
</Router>
);
}
export default App;
My MovieRow.js (which includes the link to the details page) is as follows:
import React from "react";
import { Link } from "react-router-dom";
class MovieRow extends React.Component {
render() {
return (
<div>
<table key={this.props.movie.id}>
<tbody>
<tr>
<td>
<img width="150" alt="poster" src={this.props.movie.poster_src} />
</td>
<td>
<h3>{this.props.movie.title}</h3>
<p>{this.props.movie.overview}</p>
<Link to={`/moviedetails/${this.props.movie.id}`}>
View Movie Details
</Link>
</td>
</tr>
</tbody>
</table>
</div>
);
}
}
export default MovieRow;
My MovieDetails component (which is to be returned when link to details is clicked on) is not yet connected to the API and only contains the following:
import React from "react";
import { Link } from "react-router-dom";
class MovieDetails extends React.Component {
render() {
return (
<div>
movie details
</div>
);
}
}
export default MovieDetails;
Hi William welcome to the StackOverflow community:
Can you please check your console if you are getting any kind of error or something:
as this POC: https://codesandbox.io/s/blissful-dust-nrcrj works fine with the following components.
index.js
---------
import React from "react";
import ReactDOM from "react-dom";
import { BrowserRouter as Router, Route, Switch } from "react-router-dom";
import Rated from "../components/Rated";
import Home from "./Home";
function App() {
return (
<Router>
<Switch>
<Route path="/" component={Home} exact />
<Route path="/rated" exact component={Rated} />
</Switch>
</Router>
);
}
export default App;
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
Home.js
-------
import React from "react";
import { withRouter } from "react-router";
const Home = props => {
return (
<button onClick={() => props.history.push("/rated")}>GOTO RATED</button>
);
};
export default withRouter(Home);
Rated.jsx
---------
import React from "react";
const Rated = () => <h1>Rated</h1>;
export default Rated;
I'm using react-router to direct a set of cards on the main page, to other individual pages. However, when I click on a card, the new page renders underneath the set of cards, when what I want is to render ONLY the new page. I think the problem may have to do with that my App.js holds the main page inside it, but I don't know where I should put it, if there should be a separate link to it, etc? I would appreciate any help! Thank you
here is the code for the App.js
import React from 'react';
import Routes from '../containers/routes.js';
import ProjectCards from '../containers/project_cards.js';
export default class App extends React.Component {
render() {
return(
<div>
<ProjectCards />
<Routes />
</div>
);
}
}
here is the main container:
import React from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import ProjectCard from '../components/project_card.js';
import Project1 from '../components/project1.js';
class ProjectCards extends React.Component {
render() {
var projectCards = this.props.projects.map((project, i) => {
return (
<div key={i}>
<Link to={`/${project.title}`}>
<ProjectCard title={project.title} date={project.date} focus={project.focus}/>
</Link>
</div>
);
});
return (
<div>{projectCards}</div>
);
}
}
function mapStateToProps(state) {
return {
projects: state.projects
};
}
export default connect(mapStateToProps)(ProjectCards);
here is the routes container:
import React from 'react';
import Project1 from '../components/project1.js';
import { connect } from 'react-redux';
import { Route, Switch } from 'react-router-dom';
import { withRouter } from 'react-router';
class Routes extends React.Component{
render() {
var createRoutes = this.props.projects.map((project, i) => {
return <Route key={i} exact path={`/${project.title}`} exact component={Project1}/>
});
return (
<Switch>
{createRoutes}
</Switch>
);
}
}
function mapStateToProps(state) {
return {
projects: state.projects
};
}
export default withRouter(connect(mapStateToProps)(Routes));
Set you App file as entry for all components e.g
import React, { Component } from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Home from '../../ui/components/user/home/Home.jsx';
import Header from './header/Header.jsx';
import Fakebook from '../../ui/components/user/fakebook/Fakebook.jsx';
import Dashboard from '../../ui/components/user/dashboard/Dashboard.jsx';
import NotFound from '../../ui/pages/NotFound.jsx';
export default class App extends Component{
render(){
return (
<BrowserRouter>
<div>
<Header />
<Switch>
<Route exact path="/" component={Fakebook}/>
<Route exact path="/Home" component={Home}/>
<Route exact path="/Dashboard" component={Dashboard} />
<Route exact path="/Dashboard/:userId" component={Dashboard}/>
<Route component={NotFound}/>
</Switch>
</div>
</BrowserRouter>
)
}
}
Now if you studied it you will notice a <Header /> component which is not in a route. I did it that way because my header is constant across my whole app.
This is how I setup my route I make my Route the second file after the index.js file so all my route can be visible.
I have an app that I am creating and am wondering how you would insert variables into the <Route path={insert variable here} component={myProfile}> I am trying to create a myProfile page and I am trying to get it so when they click onto the link, it redirects them to http://mywebsite.com/userId but when I try to create a Route with a variable in the path argument, it does not return the component I am trying to render when on that path.
routes.js
import { Meteor } from "meteor/meteor"
import React from "react";
import { withRouter, Switch, BrowserRouter, Route, Redirect, Link } from "react-router-dom";
import Login from "../ui/authentication/Login";
import Signup from "../ui/authentication/Signup";
import Home from "../ui/Home";
import { SubjectRoutes } from "../ui/subjectRoutes/subjectRoutes";
import AddNote from "../ui/AddNote";
import myProfile from "../ui/myProfile";
import NotFound from "../ui/NotFound";
export default class Routes extends React.Component{
renderSubjectRoutes(subjects){
return subjects.map((subject) => {
return <Route key={subject.name} path={subject.path} component={subject.component}/>
})
}
render(){
return (
<div>
<BrowserRouter>
<Switch>
<Login path="/login" />
<Signup path="/signup" />
<Route path="/" component={Home} exact/>
{this.renderSubjectRoutes(SubjectRoutes)}
<AddNote path="/addNote"/>
<myProfile path={Meteor.userId()} /> //<-- Here
<NotFound />
</Switch>
</BrowserRouter>
</div>
)
}
}
Menu.js
import { Meteor } from "meteor/meteor"
import React from "react";
import { withRouter, Link } from "react-router-dom";
import { SubjectRoutes } from "./subjectRoutes/subjectRoutes";
import AddNote from "./AddNote";
class Menu extends React.Component{
renderMenu(items){
return items.map((item) => {
return <p key={item.name}><Link to={item.path}>{item.name}</Link></p>
})
}
render(){
return(
<div>
<h1>Menu</h1>
{this.renderMenu(SubjectRoutes)}
<p><Link to="/addNote">Add a Note</Link></p>
<p><Link to={Meteor.userId()}>My Profile</Link></p>
</div>
)
}
}
export default withRouter(Menu)
You are creating way more work for yourself, and this is the wrong way to add variables to route. What you're looking to do is add params to your route. In your case, you would want it to look something like this.
<Route path="/user/:userId" />
The : is what denotes that it is a parameter, ready to render a path based on the userId. So if you went to route /user/123 - it would be able to render user 123's data.
Here's some documentation to help you out.
https://reacttraining.com/react-router/web/example/url-params