Why is match missing from props? - reactjs

I'm writing my first react application and I wanna use a Switch to show the component corresponding to the route. One of the routes uses a param. The problem is that the match attribute is missing from props so route matching doesn't seem to work (No component is inserted).
When I try to console.log this.props.match it returns undefined.
import { Switch, Route } from 'react-router-dom';
import React, { Component } from 'react';
import Index from './Index';
import Debate from './Debate';
class App extends Component {
componentDidMount() {
console.log(this.props.match); // I get undefined
}
render() {
return (
<div className="App">
<Switch>
<Route path="/debats" component={Index} />
<Route path="/debat/:debateSlug" component={Debate} />
</Switch>
</div>
);
}
}
export default withConfig(App);
I want to be able to access the match attribute so that the correct component is displayed.

Add to this in your Component
import {withRouter} from 'react-router-dom';
export default withRouter(withConfig(App));

Related

How to get the React router path on route change

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>;
}

Render function is not called

I am trying to get my react component to render in Meteor. I don't see any error messages or anything in the console, however, the component doesn't seem to display.
I am using react-router. I added log statements and it appears that the renderRoutes() function does get called, also, I see errors in the console when I change the directories for my imports (I get an error if I change the first import statement to import {Home} from '../home/blah'). I am not really sure what to try next.
Here is my router, which is in client/imports/lib/router.js.
import React from 'react';
import { Router, Route, Switch } from 'react-router';
import {createBrowserHistory} from 'history';
import {Home} from '../home/home';
import {Login} from '../login/login';
import {Connect} from '../connect/connect';
const browserHistory = createBrowserHistory();
export const renderRoutes = () => (
<Router history={browserHistory}>
<Switch>
<Route exact path="/" component={Home}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/connect" component={Connect}/>
</Switch>
</Router>
);
Here is my home page. The other pages have a similar structure. The home page is in client/imports/home/home.js.
import React, { Component } from 'react';
export default class Home extends Component {
constructor(){
super()
this.state = {
}
}
render() {
return (
<div><h1>hello from the home page</h1></div>
);
}
}
Finally, this is my main.js. It's in client/main.js.
import { Meteor } from 'meteor/meteor';
import { render } from 'react-dom';
import { renderRoutes } from './imports/lib/router.js';
import './main.html';
Meteor.startup(() => {
render(renderRoutes(), document.getElementById('app'));
});
Again, I don't see any error messages. The home page just doesn't render. I put console.log's in the constructor for the Home component and I do not see anything. I'm not sure if there is something about React that I am not understanding or if I need to change the way I am using the router.
Please let me know what I should try next, and if there is any more information I should include.
Thanks!
If you're exporting component using export default
export default class Home extends Component {
then you should import it this way:
import Home from '../home/home';
Read more about named and default exports
For the future - back to the source, check original code (from docs) first (usually working) - it's not hard to see the difference ;)

How to make using of react-router-dom for routing in Reactjs?

I have made 3 components
1)Navbar
2)Content
3)Pagination
On home page I want to display all 3 components.
I have made another component Matchinfo which should get displayed when we click on view stats button (see screenshot for more clarification) .
In app.js how should I make use of Routes so that 3 components will get display on home page i.e localhost:3000/ and when I click on view stats button it should render component Matchinfo.
In app.js :
import React, { Component } from 'react';
import { Route, NavLink, HashRouter } from "react-router-dom";
import './App.css';
import Navbar from './components/navbar';
import Content from './components/content';
import Pagination from './components/pagination';
import Matchinfo from './components/matchinfo';
class App extends Component {
render() {
return (
<div className="App">
<div className="content">
<Route path="/" component={Navbar, Content, Pagination}/>
<Route path="/match" component={Matchinfo}/>
</div>
</div>
);
}
}
export default App;
You no need to call these components in app.js using routes. I would request you to create sepearte component like Home(see example below home.js).
Then, In app.js call Home component
import Home from './components/home';
<Route path="/" component={Home}/>
create home.js under components
Call Navbar, Content annd Pagination components in Home component
import React, {Component} from "react";
import Navbar from './components/navbar';
import Content from './components/content';
import Pagination from './components/pagination';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
}
}
componentWillMount() {
}
render() {
return (
<div>
<Navbar/>
<Content />
<Pagination/>
</div>
)
}
}
export default Home;
Since you want to display Navbar, Content annd Pagination components in home page so do it like above way. Here Home is your parent component and Navbar, Content annd Pagination are child components to Home.
One route is enough mostly for one web page and in React most of times you will play with child components. You no need to configure all the components with routes.
There are several ways achieving the result.
The first one is using render method for home Route. Also, use exact attribute of Route to ensure the location is matched exactly.
import React, { Component } from 'react';
import { Route, NavLink, HashRouter } from "react-router-dom";
import './App.css';
import Navbar from './components/navbar';
import Content from './components/content';
import Pagination from './components/pagination';
import Matchinfo from './components/matchinfo';
class App extends Component {
render() {
return (
<div className="App">
<div className="content">
<Route path="/" render={(props) => (
<React.Fragment>
<Navbar/>
<Content />
<Pagination/>
<React.Fragment/>
)} exact/>
<Route path="/match" component={Matchinfo} exact/>
</div>
</div>
);
}
}
export default App;
The second one, create auxiliary component Home, for example, and include it in your route, like this:
<Route path="/" component={Home} exact/>

How to re-render a react component from out side that component

Below is my react code. I have an edit profile route which allows editing the user profile. On completing the mutation request, I want to update the user details (user avatar, firstname and lastname) in header component. How is this done?
import React from 'react';
import Relay from 'react-relay';
import { IndexRoute, Route } from 'react-router';
import Header from './header';
import Sidebar from './sidebar';
import Footer from './footer';
import Query from './Query';
import EditProfile from './routes/Profile';
class App extends React.Component { render() {
return (
<Container {...this.props}>
<Sidebar />
<Header />
<div id='body'>
{this.props.children}
</div>
<Footer />
</Container>
); } }
export default (
<Route path='/' component={App}>
<IndexRoute component={EditProfile} queries={Query} />
</Route>
);
This is basic react communication, and there are several standard ways how to do that. You are already aware that you can pass data from parent to child by using props and refs (probably aware).
To achieve the communication other way around (from child to parent), standard and most simple way is to provide callback inside prop:
class SomeParent extends Component {
// This method is using es6 class properties
// in order to skip .bind(this)
handleChildFunc(someData) => {
console.log(someData)
}
render() {
return <SomeChild someFunc={this.handleChildFunc(this)} />
}
}
Then in the child component you can just do :
this.props.someFunc()
There are also other methods like using the redux/flux store and communicate trough them, using observer pattern etc.
More about this can be read here React component communication

React pass dynamic state to all routes in router

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.

Resources