I'm using React Router to create a multi page app. My main component is <App/> and it renders all of the routing to to child components. I'm trying to pass props via the route, and based on some research I did, the most common way for child components to tap into props passed down is via the this.props.route object that they inherit. However, this object is undefined for me. On my render() function in the child component, I console.log(this.props) and am return an object that looks like this
{match: Object, location: Object, history: Object, staticContext: undefined}
Doesn't look like the props I expected at all. Here is my code in detail.
Parent Component (I'm trying to pass the word "hi" down as a prop called "test" in all of my child components):
import { BrowserRouter as Router, HashRouter, Route, Switch } from 'react-router-dom';
import Link from 'react-router';
import React from 'react';
import Home from './Home.jsx';
import Nav from './Nav.jsx';
import Progress from './Progress.jsx';
import Test from './Test.jsx';
export default class App extends React.Component {
constructor() {
super();
this._fetchPuzzle = this._fetchPuzzle.bind(this);
}
render() {
return (
<Router>
<div>
<Nav />
<Switch>
<Route path="/" exact test="hi" component={Home} />
<Route path="/progress" test="hi" component={Progress} />
<Route path="/test" test="hi" component={Test} />
<Route render={() => <p>Page not found!</p>} />
</Switch>
</div>
</Router>
);
}
}
Child:
import React from 'react';
const CodeMirror = require('react-codemirror');
import { Link } from 'react-router-dom';
require('codemirror/mode/javascript/javascript')
require('codemirror/mode/xml/xml');
require('codemirror/mode/markdown/markdown');
export default class Home extends React.Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
const options = {
lineNumbers: true,
theme: 'abcdef'
// mode: this.state.mode
};
console.log(this.props)
return (
<div>
<h1>First page bro</h1>
<CodeMirror value='code lol' onChange={()=>'do something'} options={options} />
</div>);
}
}
I'm pretty new to React so my apologies if I'm missing something obvious.
Thanks!
You can pass props to the component by making use of the render prop to the Route and thus inlining your component definition. According to the DOCS:
This allows for convenient inline rendering and wrapping without the
undesired remounting explained above.Instead of having a new React
element created for you using the component prop, you can pass in a
function to be called when the location matches. The render prop
receives all the same route props as the component render prop
So you can pass the prop to component like
<Route path="/" exact render={(props) => (<Home test="hi" {...props}/>)} />
and then you can access it like
this.props.test
in your Home component
P.S. Also make sure that you are passing {...props} so that the
default router props like location, history, match etc are also getting passed on to the Home component
otherwise the only prop that is getting passed down to it is test.
Related
What is the simplest way to pass state while using React Router? My Navi component below is reflecting user being null, as opposed to user being "KungLoad". Thanks.
class App extends Component{
constructor() {
super();
this.state = {user: "KungLoad"};
}
render () {
return(
<div>
<Router>
<Route exact path="/" state component = {Navi} />
</Router>
The simplest way is that you can pass the state as props and then use it in the specified component. For your case, you have to use render instead of component for passing the state as props.
<Route exact path="/" render={() => <Navi user={this.state.user} />} />
This will work but I would recommend to you that the Context API concept of reactJS would be best suited here. You can pass the state or props to all the component using the data provider and all the components will consume the state or props that are being provided by the parent component. . https://reactjs.org/docs/context.html
version 6 react-router-dom
I know the question got answered but I feel this might be helpful example for those who want to use functional components and they are in search of passing data between components using react-router-dom v6.
Let's suppose we have two functional components, first component A, second component B. The component A wants to share data to component B.
usage of hooks: (useLocation,useNavigate)
import {Link, useNavigate} from 'react-router-dom';
function ComponentA(props) {
const navigate = useNavigate();
const toComponentB=()=>{
navigate('/componentB',{state:{id:1,name:'sabaoon'}});
}
return (
<>
<div> <a onClick={()=>{toComponentB()}}>Component B<a/></div>
</>
);
}
export default ComponentA;
Now we will get the data in Component B.
import {useLocation} from 'react-router-dom';
function ComponentB() {
const location = useLocation();
return (
<>
<div>{location.state.name}</div>
</>
)
}
export default ComponentB;
Note: you can use HOC if you are using class components as hooks won't work in class components.
Yiu can pass your state as props to your Navi component like this: <Route exact path="/" render={() => <Navi user={this.state.user} />} />
The other answers are correct, you should pass state down to children components via props. I am adding my answer to highlight one additional way that the Route component can be used. The code looks cleaner and is easier to read if you simply add children to a Route component, rather than use the render or component prop.
class App extends Component {
constructor(props) {
super(props);
this.state = {
user: "KungLoad"
};
}
render() {
return (
<div>
<Router>
<Route exact path="/">
<Navi user={this.state.user} />
</Route>
</Router>
</div>
);
}
}
After making the state and assigning value
this.state = {user: "KungLoad"};
Passing the state value to the router is done like this.
<Router>
<Route exact path="/" render={()=> (<Navi user={this.state.user}/>)} />
</Router>
Or if you want to user is not logged in use a redirect
<Route exact path="/signin" render={()=> (<Redirect to='/signin'/>)}/>
I'm using React Router to create a multi page app. My main component is <App/> and it renders all of the routing to to child components. I'm trying to pass props via the route, and based on some research I did, the most common way for child components to tap into props passed down is via the this.props.route object that they inherit. However, this object is undefined for me. On my render() function in the child component, I console.log(this.props) and am return an object that looks like this
{match: Object, location: Object, history: Object, staticContext: undefined}
Doesn't look like the props I expected at all. Here is my code in detail.
Parent Component (I'm trying to pass the word "hi" down as a prop called "test" in all of my child components):
import { BrowserRouter as Router, HashRouter, Route, Switch } from 'react-router-dom';
import Link from 'react-router';
import React from 'react';
import Home from './Home.jsx';
import Nav from './Nav.jsx';
import Progress from './Progress.jsx';
import Test from './Test.jsx';
export default class App extends React.Component {
constructor() {
super();
this._fetchPuzzle = this._fetchPuzzle.bind(this);
}
render() {
return (
<Router>
<div>
<Nav />
<Switch>
<Route path="/" exact test="hi" component={Home} />
<Route path="/progress" test="hi" component={Progress} />
<Route path="/test" test="hi" component={Test} />
<Route render={() => <p>Page not found!</p>} />
</Switch>
</div>
</Router>
);
}
}
Child:
import React from 'react';
const CodeMirror = require('react-codemirror');
import { Link } from 'react-router-dom';
require('codemirror/mode/javascript/javascript')
require('codemirror/mode/xml/xml');
require('codemirror/mode/markdown/markdown');
export default class Home extends React.Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
const options = {
lineNumbers: true,
theme: 'abcdef'
// mode: this.state.mode
};
console.log(this.props)
return (
<div>
<h1>First page bro</h1>
<CodeMirror value='code lol' onChange={()=>'do something'} options={options} />
</div>);
}
}
I'm pretty new to React so my apologies if I'm missing something obvious.
Thanks!
You can pass props to the component by making use of the render prop to the Route and thus inlining your component definition. According to the DOCS:
This allows for convenient inline rendering and wrapping without the
undesired remounting explained above.Instead of having a new React
element created for you using the component prop, you can pass in a
function to be called when the location matches. The render prop
receives all the same route props as the component render prop
So you can pass the prop to component like
<Route path="/" exact render={(props) => (<Home test="hi" {...props}/>)} />
and then you can access it like
this.props.test
in your Home component
P.S. Also make sure that you are passing {...props} so that the
default router props like location, history, match etc are also getting passed on to the Home component
otherwise the only prop that is getting passed down to it is test.
I'm using React Router to create a multi page app. My main component is <App/> and it renders all of the routing to to child components. I'm trying to pass props via the route, and based on some research I did, the most common way for child components to tap into props passed down is via the this.props.route object that they inherit. However, this object is undefined for me. On my render() function in the child component, I console.log(this.props) and am return an object that looks like this
{match: Object, location: Object, history: Object, staticContext: undefined}
Doesn't look like the props I expected at all. Here is my code in detail.
Parent Component (I'm trying to pass the word "hi" down as a prop called "test" in all of my child components):
import { BrowserRouter as Router, HashRouter, Route, Switch } from 'react-router-dom';
import Link from 'react-router';
import React from 'react';
import Home from './Home.jsx';
import Nav from './Nav.jsx';
import Progress from './Progress.jsx';
import Test from './Test.jsx';
export default class App extends React.Component {
constructor() {
super();
this._fetchPuzzle = this._fetchPuzzle.bind(this);
}
render() {
return (
<Router>
<div>
<Nav />
<Switch>
<Route path="/" exact test="hi" component={Home} />
<Route path="/progress" test="hi" component={Progress} />
<Route path="/test" test="hi" component={Test} />
<Route render={() => <p>Page not found!</p>} />
</Switch>
</div>
</Router>
);
}
}
Child:
import React from 'react';
const CodeMirror = require('react-codemirror');
import { Link } from 'react-router-dom';
require('codemirror/mode/javascript/javascript')
require('codemirror/mode/xml/xml');
require('codemirror/mode/markdown/markdown');
export default class Home extends React.Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
const options = {
lineNumbers: true,
theme: 'abcdef'
// mode: this.state.mode
};
console.log(this.props)
return (
<div>
<h1>First page bro</h1>
<CodeMirror value='code lol' onChange={()=>'do something'} options={options} />
</div>);
}
}
I'm pretty new to React so my apologies if I'm missing something obvious.
Thanks!
You can pass props to the component by making use of the render prop to the Route and thus inlining your component definition. According to the DOCS:
This allows for convenient inline rendering and wrapping without the
undesired remounting explained above.Instead of having a new React
element created for you using the component prop, you can pass in a
function to be called when the location matches. The render prop
receives all the same route props as the component render prop
So you can pass the prop to component like
<Route path="/" exact render={(props) => (<Home test="hi" {...props}/>)} />
and then you can access it like
this.props.test
in your Home component
P.S. Also make sure that you are passing {...props} so that the
default router props like location, history, match etc are also getting passed on to the Home component
otherwise the only prop that is getting passed down to it is test.
I'm using React Router to create a multi page app. My main component is <App/> and it renders all of the routing to to child components. I'm trying to pass props via the route, and based on some research I did, the most common way for child components to tap into props passed down is via the this.props.route object that they inherit. However, this object is undefined for me. On my render() function in the child component, I console.log(this.props) and am return an object that looks like this
{match: Object, location: Object, history: Object, staticContext: undefined}
Doesn't look like the props I expected at all. Here is my code in detail.
Parent Component (I'm trying to pass the word "hi" down as a prop called "test" in all of my child components):
import { BrowserRouter as Router, HashRouter, Route, Switch } from 'react-router-dom';
import Link from 'react-router';
import React from 'react';
import Home from './Home.jsx';
import Nav from './Nav.jsx';
import Progress from './Progress.jsx';
import Test from './Test.jsx';
export default class App extends React.Component {
constructor() {
super();
this._fetchPuzzle = this._fetchPuzzle.bind(this);
}
render() {
return (
<Router>
<div>
<Nav />
<Switch>
<Route path="/" exact test="hi" component={Home} />
<Route path="/progress" test="hi" component={Progress} />
<Route path="/test" test="hi" component={Test} />
<Route render={() => <p>Page not found!</p>} />
</Switch>
</div>
</Router>
);
}
}
Child:
import React from 'react';
const CodeMirror = require('react-codemirror');
import { Link } from 'react-router-dom';
require('codemirror/mode/javascript/javascript')
require('codemirror/mode/xml/xml');
require('codemirror/mode/markdown/markdown');
export default class Home extends React.Component {
constructor(props) {
super(props);
console.log(props)
}
render() {
const options = {
lineNumbers: true,
theme: 'abcdef'
// mode: this.state.mode
};
console.log(this.props)
return (
<div>
<h1>First page bro</h1>
<CodeMirror value='code lol' onChange={()=>'do something'} options={options} />
</div>);
}
}
I'm pretty new to React so my apologies if I'm missing something obvious.
Thanks!
You can pass props to the component by making use of the render prop to the Route and thus inlining your component definition. According to the DOCS:
This allows for convenient inline rendering and wrapping without the
undesired remounting explained above.Instead of having a new React
element created for you using the component prop, you can pass in a
function to be called when the location matches. The render prop
receives all the same route props as the component render prop
So you can pass the prop to component like
<Route path="/" exact render={(props) => (<Home test="hi" {...props}/>)} />
and then you can access it like
this.props.test
in your Home component
P.S. Also make sure that you are passing {...props} so that the
default router props like location, history, match etc are also getting passed on to the Home component
otherwise the only prop that is getting passed down to it is test.
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.