I'm trying to figure out why the component SubPage is not rendering whenever the route path of /sub/:_id is visited (e.g. /sub/5f1c54257ceb10816a13d999). This is the first time I've worked with react routes. The :_id part should presumably accept query parameters from the URL dynamically so I cannot see why this is not working.
I can get the /subs page to fetch the API and render each sub on the page but just not each individual sub page.
The route is as follows near the bottom of App.js: <Route path={"/sub/:_id"} component={SubPage} />
Thanks for any help here. I've made a stackblitz for convenience, or you can see the relevant code below:
And subPage.js:
import React from 'react'
export class SubPage extends React.Component {
render() {
return (
<div className="sub-details-individual">
<h1 class="std-intro">Viewing a Single Subscriber</h1>
<div className="sub-specs">
<div className="sub-specs-inner">
id: {this.props.params._id}
</div>
</div>
</div>
)
}
}
And App.js:
import React, {Component} from "react";
import {navLinks} from "./components/nav-links";
import Root from "./components/Root";
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
import {SubPage} from "./components/subPage";
import ShowSubs from "./components/show-subs";
export default class App extends Component {
constructor() {
super();
this.state = {
navLinks: navLinks,
intro: "hello world",
url: "someurl"
}
}
updateURL = (newUrl) => {
this.setState({
url: newUrl
})
}
render() {
return (
<Router>
<Root navLinks={this.state.navLinks} intro={this.state.intro}></Root>
<Switch>
<Route path="/subs">
<p>subs page</p>
{/*this.updateURL('/subs') fails presumably because it causes the rerender infinitely - but how to solve?*/}
<ShowSubs />
</Route>
<Route path="/">
<p>homepage</p>
</Route>
<Route path={"/sub/:_id"} component={SubPage} />
</Switch>
<p>the url: {this.state.url}</p>
</Router>
);
}
}
Two things:
this.props.params._id will crash since you are missing match before params
this.props.match.params._id
few exact props are missing, especially in the subs path:
<Route exact path="/subs">
Note: the exact prop will be useful in the / route as well.
Related
I have this App.jsx that routes to (renders) different components.
But I have set <NavigationBar /> and an h1 tag between Router and Switch because I need to render those two components for every page.
So now what I want is to get the current route name/path name that displays on the browser address bar. This path is changing when I click on different links (Link) to render different components.
But the path value is the same / even though the path is changing for every Link click.
I even used componentDidUpdate but it didn't work as it gave the error
maximum update depth exceeded componentdidupdate
this is my App.jsx
import React, { Component } from "react";
import "./App.css";
import "./css/custom.css";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import NavigationBar from "./pages/homepage-components/1-navbar";
import HomePage from "./pages/HomePage";
import Post from "./pages/Post";
class App extends Component {
constructor(props) {
super(props);
this.state = {
currentPath: "",
};
}
componentDidMount() {
this.setState({
currentPath: window.location.pathname,
});
}
render() {
return (
<Router>
{/* --------------- Navigation Bar --------------- */}
<NavigationBar />
<h1>Path is: {this.state.currentPath}</h1>
{/* --------------- End of Navigation Bar --------------- */}
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/post" component={Post} />
</Switch>
</Router>
);
}
}
export default App;
Even though the different components are rendered as path changes, the value for this.state.currentPath doesn't update.
Can someone help, please?
useLocation hook provides current location:
function NavigationHeader() {
const location = useLocation();
return <h1>Path is: {location.pathname}</h1>;
}
I'm new to JavaScript and React. I seem to be stuck on this question, I have found information but I think that this is not what I'm really looking for perhaps someone can shed some light on the matter.
So what I'm really looking for is a way to create a "mold" page of an node/react app that will display changing information based on the URL a user submits. Say for example look at facebook (or even stackoverflow) one click on a profile of friends 'y' then the url changes to facebook.com/friends-y and if we choose another person it then changes. Thus I believe that's how they must know how to fill their template using the info provided from that URL with names pictures etc.
I saw that a blog suggests to use route another suggest using url queries more so (which I don't know how to read them once given or how to render them say such as with a onChange event sort of thing when say you click on something inside the page).
My question is: Are any of this methods useful, should I combine them I seen websites that uses both or is there another industry standard that i haven't found and perhaps comes with react?
Any guidance would be much appreciated.
First of all i assume that you have multiple component and you want to change from one component to another component via url. so you have to install react router dom
npm install --save react-router-dom
and after then import Router, Route, Link, Switch (whatever you want) from react-router-dom and give route to component inside router tag .... i mention below in my code
import React, { Component } from 'react';
import './App.css';
import Login from './component/login';
import User from './component/user';
import Signup from './component/signup';
import Notfound from './component/notfound';
import { BrowserRouter as Router, Route, Link, Switch} from "react-router-dom";
const Home = () => (
<div>
<h2>Home</h2>
</div>
);
class App extends Component {
constructor(props){
super(props);
this.state={
loggedIn : false
}
}
render() {
return (
<Router>
<div className="App">
<ul className="nav nav-pills">
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/login">LogIn</Link>
</li>
<li>
<Link to="/signup">Sign Up</Link>
</li>
<li>
<Link to="/user">User</Link>
</li>
</ul>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
<Route path="/signup" component={Signup} />
<Route path="/user" component={User} onEnter={this.requireAuth}/>
<Route path="*" component={Notfound} />
</Switch>
</div>
</Router>
);
}
}
export default App;
note : in my code i have total 5 component in my project
Login,
User,
Signup,
NotFound,
Home
for more router information you can check in this site. https://reacttraining.com/react-router/web/example/basic
import React , {Component} from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter, Route, Switch } from 'react-router-dom';
import App from './Components/Home/App'
import Digital from './Components/DigitalStrat/Digital-Strat';
import ServiceLines from './Components/Serviceline/ServiceLines';
import Operations from './Components/OperationTransformation/Operations-
Transformation';
import WhyUs from './Components/WhyUs/Why-us';
import Mission from './Components/Mission/Mission';
import OurGroup from './Components/OurGroup/OurGroup';
import Team from './Components/Team/Team';
import Projects from './Components/Projects/Projects';
import Research from './Components/Research/Research';
import News from './Components/News/News';
import Locations from './Components/Location/Locations';
import registerServiceWorker from './registerServiceWorker';
import NewsDetails from "./Components/NewsDetails/newsDetails";
import i18n from './js/i18n'
import { sliderArrow } from './js/sliderArrow';
import { menu } from './js/menu';
import {withRouter} from 'react-router';
import Coockies from './Components/Cookies/Cookies';
class ScrollToTop extends Component {
componentDidUpdate(prevProps) {
if (this.props.location !== prevProps.location) {
window.scrollTo(0, 0)
}
}
render() {
return this.props.children
}
}
export default withRouter(ScrollToTop);
ReactDOM.render(
<BrowserRouter>
<Switch>
<ScrollToTop>
<Route exact path = "/" component = {App} />
<Route exact path='/index.html' component={App}/>
<Route exact path='/Digital-Strategies.html' component={Digital} />
<Route exact path='/Service-Lines.html' component={ServiceLines} />
<Route exact path='/Operations-Transformation.html' component=
{Operations}/>
<Route exact path='/inside-the-company.html' component={WhyUs}/>
<Route exact path='/Mission.html' component={Mission}/>
<Route exact path='/Our-group.html' component={OurGroup}/>
<Route exact path='/Team.html' component={Team}/>
<Route exact path='/Projects.html' component={Projects}/>
<Route exact path ='/Research-Development.html' component = {Research}/>
<Route exact path='/News.html' component={News}/>
<Route exact path='/news-details.html/:slug' component={NewsDetails}/>
<Route exact path='/Locations.html' component={Locations}/>
<Route exact path='/cookies' component={Coockies} />
</ScrollToTop>
</Switch>
</BrowserRouter>, document.getElementById('root'));
registerServiceWorker();
This is the basic way to route the project. Feel free to ask question.
The way to handle routing in React is with React Router.
With this sort of (virtual) routing there are two main ways that routing needs to be handled.
1. The first is by rendering different components when the url changes—for example rendering a <Home/> component for "/" and an <About/> component for "/about".
An example:
import React, { Component } from 'react';
import { Switch, Route, withRouter } from 'react-router-dom';
import Home from "./pages/Home";
import About from "./pages/About";
class App extends Component {
render() {
return (
<Switch>
<Route exact path="/" component={ Home }/>
<Route path="/about" component={ About }/>
</Switch>
)
}
}
export default withRouter(App);
2. The second case, which I believe your question specifically addresses, is rendering the same component with different data depending on the url—for example having a <Profile/> component but changing its data for "/profiles/1" vs "/profiles/2".
An example:
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
class Profile extends Component {
constructor() {
super();
this.state = {
profileData: {}
}
}
componentDidMount() {
this.fetchData();
}
componentDidUpdate(prevProps) {
const currentId = this.props.match.params.id;
const prevId = prevProps.match.params.id;
if (currentId !== prevId) {
this.fetchData();
}
}
async fetchData() {
const profileId = this.props.match.params.id;
const profileData = await fetch(`http://example.com/api/profiles/${profileId}`);
this.setState({
profileData
});
}
render() {
const { profileData } = this.state;
return (
<div>
<h1>{ profileData.name }</h1>
</div>
)
}
}
export default withRouter(Profile);
Where the containing parent component of <Profile/> has a <Route/> that looks like this:
<Route path="/profiles/:id" component={ Profile }/>
Which is important so that the id is in this.props.match.params.
Note that in the above example the way to check what data to use to populate the view is by checking the :id parameter in the url. Since information about the url is passed to the <Profile/> component as a prop, we can check if the url changes in componentDidUpdate and get new data if there was a change.
Finally, both of these involve a bit of setup with React Router (basically just wrapping your <App/> in a <Router/>) but the documentation should help with that: https://reacttraining.com/react-router/web/guides/quick-start.
Hopefully this helps.
I have this piece of code:
class Base extends Component {
changeRoute = () => {
// after this, address bar gets updated but I can't see the Users
// component, only Home component.
this.props.history.push('/users');
}
render() {
return (
<div>
<MyBar />
{this.props.children}
</div>
)
}
}
class App extends Component {
render() {
return (
<Router>
<Base>
<a onClick={this.changeRoute}>Change</a>
<Route path="/home" component={Home} />
<Route path="/users" component={Users} />
</Base>
</Router>
)
}
}
However, when I try to change location by either using history.push or push from react-router-redux I can see the browser path updated but the content is not updating, it shows the original path content. I also noted that whenever I refresh the browser I can see the correct content related to the path.
When I change the code to the following, both the browser path and the content updates accordingly as expected, my question is: Why is it behaving different? if in my opinion both codes do the same thing.
class Base extends Component {
render() {
return (
<MyBar />
)
}
}
class App extends Component {
changeRoute = () => {
// after this, address bar and component are updated as expected.
this.props.history.push('/users');
}
render() {
return (
<Router>
<div>
<Base />
<a onClick={this.changeRoute}>Change</a>
<Route path="/home" component={Home} />
<Route path="/users" component={Users} />
</div>
</Router>
)
}
}
Edit:
I added to the source code the push method. This is the piece of code I'm using to export the App component:
import {withRouter} from 'react-router';
export default withRouter(App);
This is the code I ran and it is running fine. Can you please check whether there is anything I need to change in my code to reproduce your issue?
import React from 'react';
import ReactDOM from 'react-dom';
import {NavLink, BrowserRouter,Route} from 'react-router-dom';
class Base extends React.Component {
render() {
return (
<div>
<div>MyBar</div>
{this.props.children}
</div>
)
}
}
class App extends React.Component {
render() {
return (
<BrowserRouter>
<Base>
<NavLink to="/users">Change</NavLink>
<Route path="/home" render={()=>"Home"} />
<Route path="/users" render={()=>"Users"} />
</Base>
</BrowserRouter>
)
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Edit: From what I understood, you want to be able to navigate to the user page when the change link is clicked. The correct way to do it is using the NavLink control. This would not require the use of withRouter HOC which should only be used inside a Router component and not outside it.
I am using react router 4. I have two components 1- ShopLogin 2- Shopper. I am trying to redirect from ShopLogin component to Shopper component after button click.
Everything is working fine. URL is also changing after button click. I am able to see 'Hello' also.
But the problem is i am able to see both component on browser after button click. component is not refreshing. not sure why it is happening. Below are my code.
import React from 'react';
import PropTypes from 'prop-types';
export class ShopLogin extends React.Component {
constructor(props) {
super(props);
this.state = {
};
}
SignIn(e) {
e.preventDefault();
this.context.router.history.push('/shopper');
}
render() {
return (
<div>
<button onClick={this.SignIn.bind(this)}>SignIn</button>
</div>
);
}
}
ShopLogin.contextTypes = {
router: PropTypes.object
}
export default ShopLogin;
My Index.js
import React from 'react';
import ReactDOM from 'react-dom';
import ShopLogin from './ShopLogin';
import Shopper from './Shopper';
import { HashRouter,Route } from 'react-router-dom';
ReactDOM.render((
<HashRouter>
<div>
<Route path="/" component={ShopLogin} />
<Route path="/shopperlogin" component={ShopLogin} />
<Route path="/shopper" component={Shopper} />
</div>
</HashRouter>
), document.getElementById('root'))
My Shopper.js
import React, { Component } from 'react';
export class Shopper extends Component {
constructor(props)
{
super(props);
this.state = {
};
}
render()
{
return (
<div>
Hello </div>
);
}
}
export default Shopper;
It will show multiple components since on the route '/shopper'. The Routes checks successfully to the ShopLogin Component with the path '/' and it checks successfully to the Shopper Component with the path '/shopper'.
I would create a parent Component e.g. Main that just presents the child components and define the routes like this
import IndexRoute from react-router
import { HashRouter,Route, IndexRoute } from 'react-router-dom';
resort your routes to
<HashRouter>
<Route path='/' component={Main}>
<Route path='/shopper' component={Shopper} />
<IndexRoute component={ShopLogin} />
</Route>
</HashRouter>
Create your parent component for ShopLogin and Shopper components
class Main extends Component {
render(){
return (
<div>
{this.props.children}
</div>
)
}
Try to reorder your routes and use the exact attribute and wrap all the routes with a Switch.
<HashRouter>
<div>
<Switch>
<Route path="/" component={ShopLogin} />
<Route exact path="/shopper" component={Shopper} />
<Route path="/shopperlogin" component={ShopLogin} />
</Switch>
</div>
</HashRouter>
I'm trying to pass a dynamic state to all the routes in a React router, specifically a shopping cart (an array of objects).
The layout is I have a parent component which contains the router and all the routes, and in that I want to store the cart in state and pass it to the routes (so essentially all routes will have access to it). I've been trying a few different things and troubleshooting it by looking it up on forums for a while but I just can't get it. This is the latest setup I have:
- Main.jsx
// This is the app entry point
import React, { Component } from 'react';
import { render } from 'react-dom';
import RouterHub from './RouterHub.jsx';
render((
<RouterHub />
), document.getElementById('root'));
- RouterHub.jsx
import React, { Component } from 'react';
import { render } from 'react-dom';
import { Router, Route, hashHistory } from 'react-router'
import Home from './Home.jsx';
import Dogs from './Pages/Other.jsx';
class RouterHub extends Component {
constructor(props) {
super(props);
this.addItem = this.addItem.bind(this);
this.state = {
cart: []
};
}
addItem(item) {
let newCart = this.state.cart.splice();
newCart.push(item);
this.setState({cart: newCart});
}
render() {
return(
<Router history={hashHistory}>
<Route path="/" component={Home} cart={this.state.cart} addItem={this.addItem} />
<Route path="/other" component={Other} cart={this.state.cart} addItem={this.addItem}/>
</Router>
);
}
}
export default RouterHub;
- Home.jsx
import React, { Component } from 'react';
import Slideshow from './Home/Slideshow.jsx';
import Navbar from './Constants/Navbar.jsx';
import Footer from './Constants/Footer.jsx';
class Home extends Component {
constructor(props) {
super(props);
}
render() {
return(
<div>
<button onClick={() => this.props.route.addItem('potato')}>click me</button>
<Navbar />
// All the JSX content, I've removed to make it succint
<Footer />
</div>
);
}
}
export default Home;
Essentially what I'm wanting is in Home.jsx, when I click that button, I want another potato added to the cart. However, with this setup I get the error:
bundle.js:46451 Warning: [react-router] You cannot change <Router routes>; it will be ignored
How do I get it so that updating state in the RouterHub passes that to the routes, or is that not possible and I'm doing this all the wrong way?
Thanks for any help
Since you already have a main component for holding your state, you should insert that in the top level Route component something like this:
render((
<Router history={browserHistory}>
<Route path="/" component={RouterHub}>
<Route path="home" component={Home}/>
</Route>
</Router>
), document.getElementById('root'))
Then in your RouterHub component, pass those clone each children components with props, something like this:
{
React.Children.map( this.props.children, (child) => {
return React.cloneElement(child, this.props)
})
}
Bumping into this kind of problems will make you think of using some state management libraries like Redux/Flux.