Issues passing props via react-router-dom - reactjs

I am attempting to pass data via react-router-dom, specifically I wanted to hold state data in the App.js file which I am using to route to different pages. I can't get the props to pass. What am I doing off here? Below is an example of what I am trying to do:
App.js
import React, { Component } from 'react';
import Home from './Home';
import {BrowserRouter as Router, Route,Switch, withRouter } from 'react-router-dom';
class App extends Component {
constructor(props) {
super(props);
this.state = {
testProps:7
}
}
render() {
return (
<Router>
<div>
<Route
exact path="/"
component = {Home}
render={(props) => <Home testProps={this.state.testProps} {...props} />}/>
</div>
</Router>
);
}
}
export default App;
Home.js
import React, { Component } from 'react';
class Home extends Component {
render() {
return (
<div>
{`passing props from state: ${this.props.testProps}`}
</div>
);
}
}
export default Home;
In my home page I see: passing props from state: undefined. Am I approaching this incorrectly?

Related

How to change page title on separate header component depending on route with React?

I am using React and have my project structured in a way that I have layout components and then the main page components. I want to change the title of the page in the header component depending on which route the user came to.
Here is my App.jsx:
import React, { Suspense, lazy, Component } from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import Header from './layout/Header.jsx';
import Footer from './layout/Footer.jsx';
const Home = lazy(() => import('./pages/Home.jsx'));
const Weather = lazy(() => import('.pages/Weather.jsx'));
const Encryption = lazy(() => import('./pages/Encryption.jsx'));
const Video = lazy(() => import('./pages/Video.jsx'));
class App extends Component {
render() {
return (
<Router>
<>
<Header/>
<Suspense fallback={<div>Loading...</div>}>
<Switch>
<Route exact path="/" component={Home}/>
<Route path="/weather" component={Weather}/>
<Route path="/encryption" component={Encryption}/>
<Route path="/video" component={Video}/>
</Switch>
</Suspense>
<Footer/>
</>
</Router>
);
}
}
export default App;
My Header.jsx component is like so:
import React, { Component } from 'react';
class Header extends Component {
constructor(props) {
super(props);
}
render() {
return (
<h1>Page Title</h1>
);
}
}
export default Header;
import React, { Component } from "react";
import { withRouter } from "react-router-dom";
class Header extends Component {
constructor(props) {
super(props);
}
render() {
const path = this.props.location.pathname.slice(1);
return (
<div>
<h1>{path}</h1>
</div>
);
}
}
export default withRouter(Header);
Working example here: https://codesandbox.io/s/zl3y72k0pp
thre HOC withRouter will provide the props match, location and history to your component.
then your can use location.pathname to manage the rendering of your component

How to access url parameter in a react component

I have a react component which is loaded on routing
I need to access a parameter from the url inside the components constructor
How do I do it?
can I access it like this:
class CustomCoponent extends React.Component {
constructor(props,{match}) {
}
}
You can access route parameter in react-router-dom v4.x, by getting params from the match props.
Where you define your routes,
import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';
...
<Router>
<App>
<Switch>
<Route exact path="/" component={List} />
<Route path="/:parameterToAccess" component={CustomComponent} />
</Switch>
</App>
</Router>
...
In your component,
class CustomComponent extends React.Component {
constructor(props) {
super(props);
this.routeParam = props.match.params.parameterToAccess;
}
}
if you use routing then you can specify your route to expect the parameter.
<Route path='/yourpath/:ParamName' component={CustomComponent}/>
your component needs to be wrapped in the withRouter HOC for you to access this.
import {withRouter} from 'react-router-dom';
class CustomComponent extends React.Component{
constructor(props){
}
//**ACCESS PARAMETER VALUE LIKE THIS**
sample(){
let Paramvalue=this.props.match.params.ParamName;
}
}
export default withRouter(CustomComponent);
You can do it like this:
class CustomComponent extends React.Component {
constructor({ match, ...props }) {
console.log(match.params)
}
}
As {match} is passed to the component as a prop(property) so we can access this prop as a normal prop way.
class CustomComponent extends React.Component {
console.log(this.props.match.url)
}
Routes
import logo from './logo.svg';
import './App.css';
import {BrowserRouter as Router,Route,Switch} from 'react-router-dom';
import UpdateEmployeeComponent from './components/UpdateEmployeeComponent';
function App() {
return (
<div>
<Router>
<div className="container">
<Switch>
<Route path="/update-employee/:id" component={UpdateEmployeeComponent}></Route>
</Switch>
</div>
</Router>
</div>
);
}
export default App;
Component
import React, { Component } from 'react';
class UpdateEmployeeComponent extends Component {
constructor(props){
super(props);
this.state ={
id : this.props.match.params.id
}
console.log('Employee Id ::: '+this.id);
}
render() {
return (
<div>
</div>
);
}
}
export default UpdateEmployeeComponent;

Nesting Routes in React Router 4 (Tried wrapping routes in component)

I am trying to wrap my routes so I can render something on every route, such as a header or any static content. I have looked at this post here:
Nested Routes in React Router v4
I tried wrapping my routes like they have there, but now the only thing that shows is the wrapping component, none of the children show.
So the only thing that shows is on the / and /dashboard routes:
Home Component
Dashboard
Here is the code:
Wrapping routes:
<Home>
<Switch>
<Route path="/dashboard" component={Layout} />
<Route component={NotFound} />
</Switch>
</Home>
Home component:
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>Home component</h2>
<Link to="/dashboard">Dashboard</Link>
</div>
);
}
}
export default Home;
Layout component:
import React, { Component } from 'react';
class Layout extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>Layout Component</h2>
<h2>Layout Component</h2>
</div>
);
}
}
export default Layout;
Have you tried putting {this.props.children} in your Home component?
import React, { Component } from 'react';
import { Link } from 'react-router-dom';
class Home extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<h2>Home component</h2>
<Link to="/dashboard">Dashboard</Link>
{this.props.children}
</div>
);
}
}
export default Home;
Your layout needs a component, or instruction to know where to render the children.
Otherwise the router won't know where the children routes need to appear. The child component is passed to the layout as a property called children. You need to add this where you want it to appear:
{props.children}
Like:
import React, { Component } from 'react';
class Layout extends Component {
constructor(props) {
super(props);
}
static propTypes = {
children: PropTypes.node.isRequired,
}
render() {
return (
<div>
<h2>Layout Component</h2>
{props.children}
</div>
);
}
}
export default Layout;
I personally prefer using . react router config But if you use the bare router that should do it.

Nesting relative routes with react-router

I have a categories index page which links to a products index page of products specific to that category. That much is functioning. But when I attempt to click on a product linked to a show component specific to that product I'm encountering trouble. Below is my code:
router.js
import React from 'react';
import { Router, Route, Switch } from 'react-router';
import createBrowserHistory from 'history/createBrowserHistory'
import App from './App';
import CategoriesIndexPage from './pages/categories/CategoriesIndexPage';
import ProductsIndexPage from './pages/products/ProductsIndexPage';
import ProductShow from './pages/products/ProductShow';
import LocationsPage from './pages/LocationsPage';
const history = createBrowserHistory()
const router = (
<Router history={history}>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/categories' component={CategoriesIndexPage}/>
<Route path='/locations' component={LocationsPage}/>
<Route path='/:category' component={ProductsIndexPage}>
<Route path='/:id' component={ProductShow}/>
</Route>
</Switch>
</Router>
);
export default router;
ProductIndexPage.js
import React, { Component } from 'react';
import { BWReactData } from '../../config/FirebaseConstants.js';
import Head from '../../components/Head.js';
import Foot from '../../components/Foot.js';
import ProductsIteration from './ProductsIteration';
class ProductsIndexPage extends Component {
constructor(props){
super(props);
this.state = {
allProducts: [],
loading: true,
}
}
componentDidMount() {
...
}
render() {
let allProducts = this.state.allProducts;
let loading = this.state.loading;
let categoryURL = this.props.location.state.category;
return (
<div>
<Head/>
<ProductsIteration
allProducts={allProducts}
loading={loading}
categoryURL={categoryURL}
/>
<Foot/>
</div>
)
}
}
export default ProductsIndexPage;
ProductsIteration.js
import React from 'react';
import { Link } from 'react-router-dom';
import { Col, Row } from 'react-materialize';
const ProductsIteration = props => {
let category = props.categoryURL;
if (props.loading) {
return <div>Loading...</div>
}
return (
<Row>
{props.allProducts.map(function(object) {
return (
<Col s={12} m={6} l={3} key ={object.id}>
<div style={styles.wrapper}>
<Link to={{ pathname: `${category}/${object.id}`, state: { id: object.id }}}>
<img src={object.img} style={styles.image} />
<div style={styles.description}>
<div style={styles.descriptionContent}>{object.name}</div>
</div>
</Link>
</div>
</Col>
)
})}
</Row>
)
}
export default ProductsIteration;
The link within my iteration component renders the '/:category/:id' url in my navbar but the page does nothing. This is my first project using router and any guidance would be much appreciated.
In React Router v4:
Router components are imported from 'react-router-dom' rather than 'react-router'.
The traditional <Router/> component has been replaced with the <BrowserRouter/> component, which requires no props.
Nesting routes is no longer convention. Instead, you'll have to nest your <ProductShow/> as a component prop of a <Route/> component within a <Switch/> component within your <ProductIndexPage/> component.
See below for an example.
Router.js:
// React.
import React from 'react'
// React Router DOM.
import {
BrowserRouter as Router,
Route,
Switch
} from 'react-router-dom'
// Routes.
import App from './App'
import CategoriesIndexPage from './pages/categories/CategoriesIndexPage'
import ProductsIndexPage from './pages/products/ProductsIndexPage'
import LocationsPage from './pages/LocationsPage'
// Router.
const Router = (
<Router>
<Switch>
<Route exact path='/' component={App}/>
<Route path='/categories' component={CategoriesIndexPage}/>
<Route path='/locations' component={LocationsPage}/>
<Route path='/:category/:id?' component={ProductsIndexPage}/>
</Switch>
</Router>
)
// Export.
export default Router
ProductIndexPage.js:
// React.
import React from 'react'
// BW React Data.
import {
BWReactData
} from '../../config/FirebaseConstants.js'
// Head.
import Head from '../../components/Head.js'
// Foot.
import Foot from '../../components/Foot.js'
// Products Iteration.
import ProductsIteration from './ProductsIteration'
// Product Show.
import ProductShow from './ProductShow'
// React Router DOM.
import {
Switch
} from 'react-router-dom'
// Products Index Page.
class ProductsIndexPage extends React.Component {
// Constructor.
constructor(props){
// Super Props.
super(props)
// State.
this.state = {
allProducts: [],
loading: true,
}
}
// Did Mount.
componentDidMount() {
...
}
// Render.
render() {
let allProducts = this.state.allProducts
let loading = this.state.loading
let categoryURL = this.props.location.state.category
return (
<div>
<Head/>
<ProductsIteration
allProducts={allProducts}
loading={loading}
categoryURL={categoryURL}
/>
{this.props.match.params.id ? (<ProductShow/>) : ''}
<Foot/>
</div>
)
}
}

Uncaught Invariant Violation: ReactDOM.render(): Invalid component element

I am trying to implement a navigation example using react router and stuck in an error. Please find the code
app.js
-------
import React from 'react';
import ReactDOM from 'react-dom';
import Routes from './routes';
ReactDOM.render(Routes, document.getElementById('react-container'));
routes.js
---------
import { React,Component } from 'react';
import { DefaultRoute, Link, Route, RouteHandler,Router } from 'react-router';
import Page1 from './page1';
import Home from './home';
export default class Routes extends Component {
constructor() {
super();
}
render() {
return (
<Router >
<Route path="/" component={Home}>
<Route name="page1" path="/1" component={ Page1 }/>
</Route>
</Router>
);
}
}
home.js
-------
import React, { Component } from 'react';
export default class Home extends Component {
constructor() {
super();
}
render() {
return (
<div>
<Header />
{this.props.children}
</div>
);
}
}
page1.js
--------
import React, { Component } from 'react';
export default class Page1 extends Component {
constructor() {
super();
}
render() {
return (
<div>
<h1> Page 1 </h1>
</div>
);
}
}
I have babel transformer to convert from es6 to es5 and I get the following error on loading the app,
Uncaught Invariant Violation: ReactDOM.render(): Invalid component element. Instead of passing a component class, make sure to instantiate it by passing it to React.createElement.
Can anyone help me in troubleshooting this issue ?
The problem is in your routes.js. You are wrapping your routes inside of a component, then passing that to ReactDOM.render. You should be passing the jsx directly. My suggestions would be to unwrap routes from your class, and just export the jsx.
routes.js
---------
import React from 'react'
import { Router, Route } from 'react-router'
import Page1 from './page1'
import Home from './home'
let routes =
<Router>
<Route path="/" component={Home}>
<Route name="page1" path="/1" component={Page1}/>
</Route>
</Router>
export default routes
The error is complaining that you are passing a class, rather then calling React.createElement. Remember that this:
let someElement = <div>Hello</div>
Will turn into this:
var someElement = React.createElement(
"div",
null,
"Hello"
)

Resources