withRouter Does Not passes Route props to component - javascript

Here is my navigation component:
import React from 'react'
class Navigation extends React.Component {
constructor(props) {
super(props);
this.state = {
type: 'signUp', // or login
showModal: false,
isLoggedIn: false,
}
}
...some code
render() {
const { showModal, type, isLoggedIn } = this.state
console.log(this.props.location); // all problem is this, I'm not getting it in console
return(
...some more code
)
}
}
export default withRouter(Navigation)
And here is where it it been used in app.js
class App extends React.Component {
render () {
return(
<Router>
<Fragment>
<Navigation /> // <= right there
<Switch>
<Route exact path='/' component={HomePage}/>
<Route exact path='/search' component={HomePage}/>
<Route component={Lost} />
</Switch>
</Fragment>
</Router>
)
}
}
I want to get updated route props like match and location and history in my <Navigation /> component but I get it only when the first time that component mounts on the DOM, in my other components I update the route using window.history.pushState but I am not able to get route props from withRouter after link in the browser is been updated.
I update route with window.history.pushState because:
I could not find any way to update just link in the address bar without showing user or redirecting user to new component with React router DOM (am I doing it in right way or not?)
based on that I then use window.location.pathname to add some specific stylings to some components)
Also, I read the entirety of this and this but I could not solve this issue. What am I doing wrong?

withRouter gives you the closest <Route>'s route props, and since the Navigation component is not inside a Route you will not get the route props.
You could e.g. put the Navigation component on a Route outside of the Switch that will always be visible.
Example
class App extends React.Component {
render() {
return (
<Router>
<Fragment>
<Route path="/" component={Navigation} />
<Switch>
<Route exact path="/" component={HomePage} />
<Route exact path="/search" component={HomePage} />
<Route component={Lost} />
</Switch>
</Fragment>
</Router>
);
}
}

Related

Passing function prop to child component (via Link and Route components)

I'm using pure React with a Rails API backend.
I am fetching data from API and storing state in my Trips component. I have a Link component where I am able to pass the state to my NewTrip component, however <Link> does not allow me to pass functions.
I am able to pass functions to NewPage via render method on the Route component located at './routes/Index'.
But how do I pass the function from my Trips component? It's so much easier when passing as props to the component, the Router seems to be in the way!
'routes/Index.js'
export default (
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/trips" exact component={Trips} />
<Route path="/trip" render={(routeProps)=><NewTrip {...routeProps} />}/>
<Route path="/trip/:id" exact component={Trip} />
<Route path="/trip/:id/cost" exact component={NewCost} />
<Route path="/trip/:id/edit" exact component={EditTrip} />
</Switch>
</Router>
);
'components/Trips'
class Trips extends React.Component {
constructor(props) {
super(props);
this.state = {
trips: []
}
this.addTrip = this.addTrip.bind(this);
}
addTrip(trip) {
const {trips} = this.state;
trips.push(trip);
this.setState({ trips: trips});
}
render(){
return(
<Link
to={{
pathname: "/trip",
state: {trips: trips, onAddTrip={this.addTrip}} // not allowed,
// but I want to pass this function to the
// Component which is rendered by the Route in Index.js
}}
className="btn custom-button">
Create New Trip
</Link>
)
}
}
I think you should lift state up of the Trips component and have it in your 'routes/Index.js'. (it will need to be a component now, not just an export).
'routes/Index.js'
export default class Routes extends React.Component {
constructor(props) {
super(props);
this.state = {
trips: []
}
this.addTrip = this.addTrip.bind(this);
}
addTrip(trip) {
const {trips} = this.state;
trips.push(trip);
this.setState({ trips: trips});
}
render() {
return (
<Router>
<Switch>
<Route path="/" exact component={Home} />
<Route path="/trips" exact component={Trips} />
<Route path="/trip" render={(routeProps)=>
<NewTrip addTrip={this.addTrip} trips={this.state.trips} {...routeProps} />
}/>
<Route path="/trip/:id" exact render={(routeProps)=>
<Trip addTrip={this.addTrip} trips={this.state.trips} {...routeProps} />
}/>
<Route path="/trip/:id/cost" exact component={NewCost} />
<Route path="/trip/:id/edit" exact component={EditTrip} />
</Switch>
</Router>
);
}
}
'components/Trips'
class Trips extends React.Component {
render() {
const trips = this.props.trips
return (
<Link
to={{
pathname: "/trip",
}}
className="btn custom-button">
Create New Trip
</Link>
)
}
}
It might be better to have the state even higher up in the App component, but you didn't provide that, so this has to do :)
You can pass functions using state in react router Link.
<Link
to={{
pathname: "/trip",
state: {trips: trips, onAddTrip: this.addTrip}
}}
className="btn custom-button">
Create New Trip
</Link>
And then in /trip, you retrieve and use the function like this:
this.props.location.state.addTrip();

Cannot read property state of undefined privateroute

I found online how to create a costumed private route,
However, I'm getting an error
"Cannot read property 'state' of undefined" on line 12
I'm kinda new to react and I'm having trouble understanding props vs this.
Router.js
import React, { Component } from 'react';
import { Route, BrowserRouter, Redirect } from "react-router-dom";
import Login from './Authentication/Login';
import Register from './Authentication/Register';
import PageRouter from './page/PageRouter';
import Profile from './page/Profile';
import Rankings from './page/Rankings';
import Shop from './page/Shop';
const PrivateRoute = ({ component: Component, ...rest }) => (
<Route {...rest} render={
(props) => (
this.state
? <Component {...props} />
: <Redirect to='/login' />
)} />
)
class Router extends Component{
constructor(props){
super(props);
this.state = {
login: false,
}
}
render(){
return(
<div>
<BrowserRouter>
<Route exact path="/" component={ Register }></Route>
<Route path='/register' component={ Register }/>
<Route path="/login" component={ Login } />
<PrivateRoute path='/home' component={ PageRouter } />
<Route path ='/profile' component={ Profile } />
<Route path = '/rankings' component={ Rankings } />
<Route path = '/shop' component={ Shop }/>
</BrowserRouter>
</div>
);
}
}
export default Router;
Any information would help. Thanks!
This isn't a React issue. The key you're missing here is understanding JavaScript context. Right now PrivateRoute's lexical scope is the global or window object (or if in strict mode undefined). You currently have no state on that object. If you want a way to utilize your Router class' state, then I would suggest you pass in some prop to PrivateRoute via Router.
So if you wanted to access the login property on state try something like:
<PrivateRoute path='/home' component={ PageRouter } isLoggedIn={this.state.login} />
then your PrivateRoute would have access to a prop called isLoggedIn which you could use in your ternary.
"Cannot read property 'state' of undefined" on line 12 I'm kinda new to react and I'm having trouble understanding props vs this.
Props is (in simple terms) a collection of attibutes that your component needs, eg: <MyComponent name="xxx" address="yyy"/> where name and address can be accessed by this.props.name or this.props.address respectively.
Keyword this is a different concept altogether. this referring to the component itself. It means, you can access its (component) state, props, or methods that is defined inside the component class
I don't know if this is related to your issue or not, but I noticed that your sample code is coming from a tutorial (https://tylermcginnis.com/react-router-protected-routes-authentication/).
Below is my implementation of PrivateRoute:
const PrivateRoute = ({ component: Component, ...rest }: {component: any}) => (
<Route {...rest} render={(props) => (
fakeAuth.isAuthenticated === true
? <Component {...props} />
: <Redirect to={{
pathname: '/login',
state: { from: props.location }
}} />
)} />
)
PrivateRoute.propTypes = {
component: PropTypes.any,
location: PropTypes.string,
path: PropTypes.string
};
The state properties is not this.state. It is a parameter from Redirectof react-router-dom

How to redirect to another Page using a button in Reactjs

I am trying to learn how to redirect through pages using React.
I have tried to write some code on my own but i keep getting problems. I Created a route class for the class path, and 2 classes to move through. And the route class is imported to the app class. I am not pasting any data from the second class because its a written paragraph to be displayed.
This is what i have done:
import React from 'react'
import {BrowserRouter as Router, Route, Switch} from 'react-router-dom';
import Firsttry from './firsttry'
import Comp2 from "./comp2";
const Routes = () => (
<Router>
<Switch>
<Route path="/" component={Firsttry} />
<Route path="/comp2" component={Comp2} />
</Switch>
</Router>
);
export default Routes;
Second class:
import React, { Component } from "react";
import { Redirect } from "react-router-dom";
class Firsttry extends Component {
constructor(props) {
super(props);
this.state = {
redirect: false
};
}
onclick = () => {
this.setState({
redirect: true
});
};
render() {
if (this.state.redirect) {
return <Redirect to="/comp2" />;
}
return (
<div>
<p> hello</p>
<button onClick={this.onclick}>click me</button>
</div>
);
}
}
export default Firsttry;
Switch the routes. May be always your first route is getting hit and Comp2 is never rendered.
<Switch>
<Route path='/comp2' component={Comp2} />
<Route path='/' component={Firsttry}/>
</Switch>
Or you have another option: adding exact prop to your route.
<Switch>
<Route exact path='/' component={Firsttry}/>
<Route exact path='/comp2' component={Comp2} />
</Switch>
Only one Route inside a Switch can be active at a time, and / will match every route. You can add the exact prop to the / route to make sure it will only match on the root path.
const Routes = () => (
<Router>
<Switch>
<Route exact path="/" component={Firsttry} />
<Route path="/comp2" component={Comp2} />
</Switch>
</Router>
);

ReactJS: Pass parameter from rails to react router to component

I am trying to pass a value from the render function to the component:
= react_component('App', props: {test: 'abc'}, prerender: false)
Routes.jsx
<Route path="/" component={App} >
App.jsx (component)
class App extends React.Component {
render() {
return (
<Header test={this.props.test}>
</Header>
{this.props.children}
<Footer />
);
}
}
App.propTypes = { test: PropTypes.string };
There does not seem to be a coherent answer to this complete flow.
I have tried the following:
<Route path="/" component={() => (<App myProp="value" />)}/>
But this still does not answer the question of picking up the value provided by the initial render call(react_component)
Looking for an end to end answer on how to pass a parameter from the
"view" to the "react router" to the "component"
We will start from the view:
<%= react_component('MyRoute', {test: 123}, prerender: false) %>
Now we will create a component that holds our route:
class MyRoute extends Component{
constructor(props){
super(props)
}
render(){
return(
<Switch>
<Route path="/" render={() => <App test={this.props.test} />} />
<Route path="/login" component={Login} />
</Switch>
)
}
}
As you can see, we passed the test prop from the Route component to the App component. Now we can use the test prop in the App component:
class App extends Component{
constructor(props){
super(props)
}
render(){
return(
<h1>{this.props.test}</h1>
)
}
}
<Route path="/" render={attr => <App {...attr} test="abc" />} />
In Router v3 you would do something like this
Wrap your App component under withRouter like this
import { withRouter } from 'react-router';
class App extends React.Component {
render() {
return (
<Header test={this.props.test}>
</Header>
{
this.props.children &&
React.clone(this.props.children, {...this.props} )}
<Footer />
);
}
}
App.propTypes = { test: PropTypes.string };
export const APP = withRouter(App);
And construct your routes like this...
<Route path="/" component={APP}>
<Route path="/lobby" component={Lobby} />
<Route path="/map" component={GameMap} />
...
</Route>
So your child routes will be rendered inside the APP children property an the props will be passed down to them.
Hope this helps!

Accessing parent state in child in React

I have (e.g.) two components in React. The first, app.js, is the root component. It imports some JSON data and puts it in its state. This works fine (I can see it in the React devtools).
import data from '../data/docs.json';
class App extends Component {
constructor() {
super();
this.state = {
docs: {}
};
}
componentWillMount() {
this.setState({
docs: data
});
}
render() {
return (
<Router history={hashHistory}>
<Route path="/" component={Wrapper}>
<IndexRoute component={Home} />
<Route path="/home" component={Home} />
<Route path="/docs" component={Docs} />
</Route>
</Router>
);
}
}
The second, docs.js, is meant to show this JSON data. To do that it needs to access the state of app.js. At the moment it errors, and I know why (this does not include app.js). But how then can I pass the state from app.js to docs.js?
class Docs extends React.Component {
render() {
return(
<div>
{this.state.docs.map(function(study, key) {
return <p>Random text here</p>;
})}
</div>
)
}
}
The proper way of doing this would be by passing state as props to Docs component.
However, because you are using React Router it can be accessed in a bit different way: this.props.route.param instead of default this.props.param
So your code should look more or less like this:
<Route path="/docs" component={Docs} docs={this.state.docs} />
and
{this.props.route.docs.map(function(study, key) {
return <p>Random text here</p>;
})}
Another way of doing this is:
<Route path="/docs" component={() => <Docs docs={this.state.docs}/>}>
If you need to pass children:
<Route path="/" component={(props) => <Docs docs={this.state.docs}>{props.children}</Docs>}>
If you are doing it like this, then you can access your props values directly by this.props.docs in Child Component:
{
this.props.docs.map((study, key)=> {
return <p key={key}>Random text here</p>;
})
}
Another way of doing this will be
<Route path='/' render={ routeProps => <Home
{...routeProps}
docs={this.state.docs}
/>
}
/>
While in the child component you can access docs using
this.props.docs
Hope it helps!

Categories

Resources