How to pass props in react router - reactjs

I have an App, a Navbar and a Content class, I am trying to pass a prop from navbar to content that will be rendered when I redirect to the content page.
App.js
import React, { Component } from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import Navbar from './components/Home/Navbar';
import Content from './components/Home/Content';
export default class App extends Component {
render() {
return (
<Router>
<div>
<Navbar />
<Route path="/content" component={Content} render={(props) => <Navbar {...props} test={this.state.test} />} />
</div>
</Router>
);
}
}
Navbar.js
import React from 'react';
class Navbar extends React.Component {
constructor(props) {
super(props);
this.state = {
test: 'test',
}
}
render() {
return (
<div>
This is my navbar
</div>
);
}
}
export default Navbar;
Content.js
import React from 'react';
class Content extends React.Component {
constructor(props) {
super(props);
this.state = {
x: 'x',
test: this.props.test
}
}
render() {
return (
<div>
<p>{this.state.x}</p>
<p>{this.state.test}</p>
</div>
);
}
}
export default Content;
The problem that I am having is that is when I redirect to the content page, the state from the navbar class is not being passed through to it. How do I fix this?

The problem mostly lays in the fact that you are using both component and render props in your Route, you should use only one. If you do not want to change or pass along anything from where your Route is defined, you should use component property.
If you do wish to pass along some information at that point, use the render prop as you have done (however, I believe you really wanted to render the Content component and not the NavBar as in your OP)
<Route path="/content" render={(props) => <Content {...props} test={this.state.test} />} />
Then you really don't need any of your local state you were displaying, and content could be a functional component instead, like
const Content = ({ x, test }) => (
<>
<p>{ x }</p>
<p>{ test }</p>
</>);
where x and test would be destructured from your props, giving you easy access to it (you could also use (props) and then props.test and props.x depending on how you like to write it)

u can pass state like this with redirect :
<Redirect to={{
pathname: '/content',
state: { test: '123' }
}}
/>
and for accessing it :
this.props.location.state.test

Related

How to generate custom url in React TypeScript with Class

I watched some stack overflow topic but they was always using function components. I want to know how can I generate custom url in TypeScript like http://localhost:3000/user/:userUid with Class Component.
I try this:
the path in Route is '/user/:userUID'
interface IURLInfo {
userUID: string
}
interface IProps extends RouteComponentProps<IURLInfo> {
}
interface IState {
}
class ShipsBoyBoatDashboard extends React.Component<IProps, IState> {
constructor(props: IProps) {
super(props)
}
componentDidMount() {
userIsLogged()
firebaseAuth().onAuthStateChanged(function(user) {
if(user) {
}
})
}
render() {
return(
<div className="ship-dashboard-container">
<p>{this.props.match.params.userUID}</p>
</div>
)
}
}
export default withRouter(ShipsBoyBoatDashboard)
But React send me back an error: TypeError: this.props.match is undefined
UPDATE
this is my index.tsx:
import './index.css';
import App from './App';
import { Router } from 'react-router-dom';
import history from './utils/history';
ReactDOM.render(
<React.StrictMode>
<Router history={history}>
<App />
</Router>
</React.StrictMode>,
document.getElementById('root')
);
And my App.tsx (even it is useless)
import React from 'react';
import { Switch, Route } from 'react-router-dom';
import BaseLayout from './utils/baseLayout';
import routes from './routes';
export default class extends React.Component {
state = {
showNavbar: true
}
showNavbar = (showNavbar = true) => {
this.setState({ showNavbar });
}
render() {
return (
<BaseLayout showNavbar={this.state.showNavbar}>
<Switch>
{routes.map(route => (
<Route
exact
key={route.path}
path={route.path}
render={() => (
<route.component
showNavbar={() => this.showNavbar(route.showNavbar)}
/>
)}
/>
))}
</Switch>
</BaseLayout>
);
}
}
The issue is your use of the render prop. See the documentation here.
The function you pass to render takes the react-router injected route props (i.e. the match prop and others) as an argument, but you then need to manually pass those props through to the component you're rendering in the function. That doesn't happen automatically.
This is unlike using the component prop where the route props are automatically injected into the component by react-router - that might be what you've seen in other examples.
Try this
render={(routeProps) => ( // routeProps is an argument to the render function
<route.component
showNavbar={() => this.showNavbar(route.showNavbar)}
{...routeProps} // you need to pass them through to the rendered component
/>
)}
Or, to demonstrate passing match more directly...
render={({ match }) => (
<route.component
showNavbar={() => this.showNavbar(route.showNavbar)}
match={match}
/>
)}

Issues passing props via react-router-dom

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?

I am trying to go back to the previous page on click of a button in react

import {BrowserRouter as Router, Route} from 'react-router-dom';
import Home from './Home';
class App extends Component {
constructor(props){
super(props);
this.state = {value: true}
this.goBack = this.goBack.bind(this);
}
goBack() {
this.props.history.goBack();
}
render() {
return (
<Router>
<div className="App">
<div className="App-header">
<button onClick={this.goBack}>Go Back</button>
</div>
<Route path="/" exact render={() => <Home value={this.state.value}/>}/>
<Route path="/details/:id" component={DetailView}/>
</div>
</Router>
);
}
}
export default App;
This is code. On click of Back button i want to take me to the previous age. But this goBack() is not working for me. Probably I am making some mistake in using it.I tried couple of ways from guthub and stackover flow but nothing worked.
can you try adding withRouter
import {..., withRouter} from 'react-router-dom';
then change export to
export default wihRouter(App);
App component does not receive history as prop because the Router is rendered inside it, instead you can create a wrapper component that is in the route to use this.props.history.
class App extends Component {
render() {
return (
<Router>
<Route path="/" component={Content} />
</Router>
)
}
}
For the content component:
class Content extends Component {
constructor(props){
super(props);
this.state = {value: true}
this.goBack = this.goBack.bind(this);
}
goBack() {
this.props.history.goBack();
}
render() {
return (
<div className="App">
<div className="App-header">
<button onClick={this.goBack}>Go Back</button>
</div>
<Route path="/" exact render={() => <Home value={this.state.value}/>}/>
<Route path="/details/:id" component={DetailView}/>
</div>
);
}
}
Now, Content component is in the route and can receive the history prop.
Another way you can handle this is to simply render the Content component in App with <Content /> and then use withRouter HOC on Content.
withRouter
PS: You cannot apply withRouter to App component because technically App is outside the Router

How to pass props into component from react-router Switch statement

I have a simple array with the possible routes in it, and then map them inside a react-dom-router <Switch> component to show the proper route that the user is on.
The question I have is:
How do I pass a prop from the route object to the component being used within the <Switch>? The key in question here is the someKey prop in the /faq route.
route.js
import Home from "../components/home/Home";
import FaqPage from "../components/faq/FaqPage";
export default [
{
path: "/",
exact: true,
component: Home
},
{
path: "/faq",
component: FaqPage,
someKey: "Test"
}
];
Body.js
import React, { Component } from "react";
import { Switch, Route } from "react-router-dom";
// Data
import routes from "../shared/routes";
class Body extends Component {
render() {
return (
<div className="main-body">
<Switch>
{routes.map((route, i) => {
// HOW DO I PASS THE 'someKey' PROP HERE?
return <Route key={i} {...route} />;
})}
</Switch>
</div>
);
}
}
export default Body;
I've tried a few different ways suggested but I've been unable to access the prop within the FaqPage component. Inside that component I tried to use the prop with a statement like this.props.someKey with no luck. Every sample I see uses a hardcoded component inside the <Route />, but I'm using a variable.
https://github.com/ReactTraining/react-router/issues/4105#issuecomment-291834881
https://github.com/ReactTraining/react-router/issues/4627#issuecomment-332972317
Any idea what I should be doing to make this happen?
You could wrap component into render function.
import React, { Component } from "react";
import { Switch, Route } from "react-router-dom";
// Data
import routes from "../shared/routes";
class Body extends Component {
render() {
return (
<div className="main-body">
<Switch>
{routes.map(({component: Cmp, ...route}, i) => {
// HOW DO I PASS THE 'someKey' PROP HERE?
return (<Route
key={i}
{...route}
render={props => <Cmp {...props} someKey="someValue" />}
/>);
})}
</Switch>
</div>
);
}
}
export default Body;
Try adding a render function into your Route Component in Body.js and access the component there-
class Body extends Component {
render() {
return (
<div className="main-body">
<Switch>
{routes.map(({component: ComponentDetails, ...route}, i) => {
// HOW DO I PASS THE 'someKey' PROP HERE?
return (
<Route
exact path='/'
key={i}
{...route}
render={(props)=>
<ComponentDetails {...props}
someKey="TEST" />)
</Switch>
</div>
);
}
}
export default Body;

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.

Resources