I want to get the location of the page I'm on in order to set up conditional rendering. Originally, I had something set up like this
const currentPath = window.location.pathname;
...
<h1>{currentPath}</h1>
And that would echo out the path as http://example.com/page.
But since I've switched to using HashRouter, and page links are generated like http://example.com/#/page, the only thing that echoes out is "/"
How do I get the location of the page after the hash?
Route in React-router v4 passes three props to the component it renders. One of these is the match object. It contains information about how the current path was matched.
In your case, you can use match.path or match.url to get the location of the page.
Something like this:
import React from 'react';
import { render } from 'react-dom';
import { Route, HashRouter as Router, Switch } from 'react-router-dom';
const Child = ({ match }) => {
return <p>{match.url}</p>;
};
const App = () => (
<Router>
<Switch>
<Route exact path='/' component={Child} />
<Route exact path='/test1' component={Child} />
<Route exact path='/test2' component={Child} />
</Switch>
</Router>
);
render(<App />, document.getElementById('root'));
Working code is available here:
https://codesandbox.io/s/3xj75z41z1
Change the route in the preview section on the right to / or /test1 or /test2, and you'll see the same path displayed on the page.
Hope this helps. Cheers! :)
React Router provides location parameter out of box.
You can access it like location.pathname
For eg: if the component is Page:
const {HashRouter, Route, Link} = ReactRouterDOM;
function Page({location}) {
return <p>{location.pathname}</p>;
}
class App extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<HashRouter>
<div>
<Route path="/page" component={Page} />
<Link to='/page'>Link to Page</Link>
</div>
</HashRouter>
);
}
}
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<script src="https://unpkg.com/react-router-dom/umd/react-router.min.js"></script>
<script src="https://unpkg.com/react-router-dom/umd/react-router-dom.min.js"></script>
<div id="root"></div>
https://reacttraining.com/react-router/web/api/location
Related
This question already has answers here:
Link tag inside BrowserRouter changes only the URL, but doesn't render the component
(2 answers)
Closed 7 months ago.
I'm attempting to use React Router to allow a button in my NavBar to change the view when a button is clicked. Specifically, I want an "Upload" button to change the URL to /upload and render the UploadPage component.
Currently, the URL will change, but the view does not automatically render, and the 'old' component is still visible. I need to manually reload the page or go to the URL directly for the view to load. How can I stop this behaviour so that it automatically renders without manual reload?
App.js:
import { Component } from "react";
import Home from "../src/components/Component/Home/Home";
import Header from "./components/Component/Header/Header";
import UploadPage from "./components/Component/VideoUpload/VideoUpload";
import { BrowserRouter, Switch, Route } from "react-router-dom";
class App extends Component {
render() {
return (
<BrowserRouter>
<Header />
<Switch>
<Route path="/" exact component={Home} />
<Route
path="/video/:videoId"
component={Home}
render={(routerProps) => <Home {...routerProps} />
/>
<Route path="/upload" component={UploadPage} />
</Switch>
</BrowserRouter>
);
}
}
export default App;
Header.js
(This is a snippet of just the button in the NavBar)
import { Link } from "react-router-dom";
const Header = () => {
return (
//NavBar code here...
<Link to="/upload">
<button>
<img draggable="false" src={uploadIcon} alt="upload-icon" />
UPLOAD
</button>
</Link>
);
};
VideoUpload.js
import React from "react";
const VideoUpload = () => {
return (
<section className="uploadContainer">
<section className="uploadContainer__titleContainer">
<h2 className="uploadContainer__title">Upload Video</h2>
</section>
</section>
);
};
export default VideoUpload;
After a lot of trial and error and research, I found that in my index.js:
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<React.StrictMode>
<App />
</React.StrictMode>
);
Should be changed to:
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
From my tests, <BroswerRouter> isn't necessary here and <App /> doesn't need to be wrapped for it to work, but, I'm keeping it wrapped just in case.
This fixes the issues I was experiencing.
I am a total React newbie and have a (probably) stupid question. How do I switch between DIFFERENT javascript pages in React.js?
I have a button on one of my pages, that I want to link to another javascript page. I know about the router, but that does not fit my needs.
Thank You,
Mark Bruckert
This is based on the example from the react-router docs. React Router is probably the easiest client side routing solution. Happy coding.
See the complete example on Stackblitz.
import React, { Component } from 'react';
import { render } from 'react-dom';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
const Nav = () => (
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
</ul>
</div>
);
const HomePage = () => <h1>Home Page</h1>;
const AboutPage = () => <h1>About Page</h1>;
class App extends Component {
constructor() {
super();
this.state = {
name: 'React'
};
}
render() {
return (
<Router>
{/* Router component can have only 1 child. We'll use a simple
div element for this example. */}
<div>
<Nav />
<Route exact path="/" component={HomePage} />
<Route path="/about" component={AboutPage} />
</div>
</Router>
);
}
}
render(<App />, document.getElementById('root'));
Use react-router to define your pages and switch between them
https://reacttraining.com/react-router/
I have a React Component called ContentBar that holds a Route to display dynamic content:
//ContentBar.js
var React = require('react')
import ContentBarRoute from '../../../../routes/contentbar.routes'
const ContentBar = () =>
(
<ContentBarRoute />
)
export default ContentBar
I've placed this ContentBar in my root App structure:
//App.js
<div className="logBar">
<ErrorBoundary>
<Responsive minWidth={960}>
<ContentBar />
</Responsive>
</ErrorBoundary>
</div>
And I've created a route for a new menu in the ContentBarRoute component which I'm loading in the ContentBar:
//ContactBarRoute.react.js
const ContentBarRoute = () => (
<main>
<Switch>
<Route exact path="/logbar"component={LogBar}/>
<Route path="/user/:number/settings" />
<Route path="/user/:number/profile" />
<Route path="/user/add" component={UserAddMenu} />
</Switch>
</main>
)
When I try to link to /user/add from another component though, I'm not able to update the route from another component:
//Contactlist.react.js
<div className="contact-list useradd">
<Button as={Link} to="/user/add" className="btn-useradd">
<FontAwesome className="icon-adduser" tag="i" name="plus" />
</Button>
</div>
Can someone help me see what I'm doing wrong here? There's not a lot of information about routing between components, I found one answer in my research but it was slightly different: React-Router-4 routing from another component
The problem is that my routes and links are in separate areas of the hierarchy, whereas that guy's components were all close together.
Update:
The other example doesn't talk about rendering new components in place of old ones where one component is totally separate from the other:
Here is my router definition it exists in the class that sends the App to the html div:
import React from 'react'
import { render } from 'react-dom'
import { Provider } from 'react-redux'
//import { createStore } from 'redux'
import { HashRouter } from 'react-router-dom'
import configureStore from '../tools/store.enhancer';
import App from '../javascripts/entry';
//import rootReducer from '../app/reducers/index'
//let store = createStore(rootReducer)
const store = configureStore();
render((
<Provider store={store}>
<HashRouter>
<App />
</HashRouter>
</Provider>
), document.getElementById('root'));
The behavior I expect is that the existing component is switched out for the user-add component, but the actual behavior is that nothing happens when I click the button, and I get an error saying
Hash history cannot PUSH the same path; a new entry will not be added to the history stack
I have the following App component.
class App extends React.Component {
constructor() {
super();
this.state = {}
}
// various methods that interact with state defined here
render() {
const Main = () => (
<div className="main-wrapper">
<ListPicker/>
<ListPane/>
</div>
);
const Search = () => (
<div className="search-wrapper">
<ul className="search-results">
<li>Search Results</li>
</ul>
</div>
);
return (
<div className="app-wrapper">
<Title/>
<SearchBar listResults={this.listResults}/>
<Route exact path="/" component={Main}/>
<Route path="/search" component={Search}/>
</div>
)
}
}
Which is rendered in index.js:
import React from 'react';
import { render } from 'react-dom';
import {
BrowserRouter as Router,
Route
} from 'react-router-dom';
import App from './components/App';
const Root = () => {
return (
<Router>
<div>
<Route exact path="/" component={App}/>
</div>
</Router>
)
};
render(<Root/>, document.getElementById('root'));
Towards the bottom of App you can see I'm trying to have either the Main component or Search component render below <Title/> and <SearchBar/> based on the paths / or /search. As far as I can tell from the React-Router docs, I'm doing what's shown in their example app, but I can't get this to work correctly. With this current setup Main renders fine at / but when navigating to /search nothing renders inside of <Root/>. I also tried wrapping those two <Routes/> in a <Switch/> but got the same result. Am I missing something?
You put a exact Route in you index.js. So the route /search can't find a way. So change to:
const Root = () => {
return (
<Router>
<div>
<Route path="/" component={App}/>
</div>
</Router>
)
};
I have 2 routes, / and /about and i've tested with several more. All routes only render the home component which is /.
When I try a route that doesn't exist it recognises that fine and displays the warning
Warning: No route matches path "/example". Make sure you have <Route path="/example"> somewhere in your routes
App.js
import React from 'react';
import Router from 'react-router';
import { DefaultRoute, Link, Route, RouteHandler } from 'react-router';
import {Home, About} from './components/Main';
let routes = (
<Route name="home" path="/" handler={Home} >
<Route name="about" handler={About} />
</Route>
);
Router.run(routes, function (Handler) {
React.render(<Handler/>, document.body);
});
./components/Main
import React from 'react';
var Home = React.createClass({
render() {
return <div> this is the main component </div>
}
});
var About = React.createClass({
render(){
return <div>This is the about</div>
}
});
export default {
Home,About
};
I've tried adding an explicit path to about to no avail.
<Route name="about" path="/about" handler={About} />
I've stumbled upon this stackoverflow Q but found no salvation in its answer.
Can anyone shed some light on what might be the problem?
Using ES6 and the newest react-router would look like this:
import React from 'react';
import {
Router,
Route,
IndexRoute,
}
from 'react-router';
const routes = (
<Router>
<Route component={Home} path="/">
<IndexRoute component={About}/>
</Route>
</Router>
);
const Home = React.createClass({
render() {
return (
<div> this is the main component
{this.props.children}
</div>
);
}
});
//Remember to have your about component either imported or
//defined somewhere
React.render(routes, document.body);
On a side note, if you want to match unfound route to a specific view, use this:
<Route component={NotFound} path="*"></Route>
Notice the path is set to *
Also write your own NotFound component.
Mine looks like this:
const NotFound = React.createClass({
render(){
let _location = window.location.href;
return(
<div className="notfound-card">
<div className="content">
<a className="header">404 Invalid URL</a >
</div>
<hr></hr>
<div className="description">
<p>
You have reached:
</p>
<p className="location">
{_location}
</p>
</div>
</div>
);
}
});
Since you've nested About under Home you need to render a <RouteHandler /> component within your Home component in order for React Router to be able to display your route components.
import {RouteHandler} from 'react-router';
var Home = React.createClass({
render() {
return (<div> this is the main component
<RouteHandler />
</div>);
}
});