Gardezi Gardezi - 3 months ago 13
Javascript Question

location missing in props (ReactJS)

I'm kind of new to reactjs and I'm learning step by step. I'm facing a problem and that is when I try to access the location parameter in the props it returns me

undefined
. I tried to find the solution but most of the people have written I have to add my component in the router but I'm wrapping it in the router but still, I don't have access to location parameter

export const abcdContainer = withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(abcd));


I'm trying to access the location parameter in the and component but the problem is there is no location parameter in it. Can somebody tell me what is it that is going wrong

Please if anybody know what is wrong please tell me I have spent half of my day and I can't figure it out

CODE AND VERSION ADDED WITH URL

Router version => 2.8.1

URL : http://localhost:3000/somePage?someParam=cm9oYW5qYWxpbHRlYWNoZXJAZ21haWwuY29t

abcdContainer.js

const mapStateToProps = (state, ownProps) => {
// some code over here
}

const mapDispatchToProps = (dispatch, ownProps) => {
// some code over here
};

export const abcdContainer = withRouter(connect(
mapStateToProps,
mapDispatchToProps
)(abcd));


abcd.jsx

class abcd extends Component {

constructor(props, context) {
super(props, context);
this.state = {
// setting state over here
};
}

abcdFunction(){
if (this.props.location.query.someParam !== undefined){ // trying to extract someParam value from location
// some code over here
}
}

render() {
// some code over here
}
}


export default CSSModules(abcd, styles, { allowMultiple: true });


Here is the flow. The router redirect to the container and then the container redirect to the real component

Route.js

export const Routes = ({ store }) => (
<Provider store={store}>
<Router history={browserHistory}>
<Route path="/" component={aContainer}>
<IndexRoute component={IContainer} />
// some routes
<Route path="/openAbcd" component={() => (<abcdContainer caller="aaaaaaa" />)} />
// some routes
</Route>

// some routes
</Router>
</Provider>
);

Routes.propTypes = {
store: React.PropTypes.object.isRequired,
};

Answer Source
<Route path="/openAbcd" component={() => (<abcdContainer caller="aaaaaaa" />)} />

If you use an inline arrow function to render your component why you don't just pass the props directly to the component? Then you will not need withRouter(). Like this:

<Route path="/openAbcd" component={props => (<abcdContainer caller="aaaaaaa" {...props} />)} />

Also the docs of react-router v2.8.1 says about withRouter():

A HoC (higher-order component) that wraps another component to provide props.router.

It doesn't provide location but router as a prop. I recommend you to update react-router to v4 or at least v3.

EDIT: "But why were the props not being inserted implicitly?":

React knows two types of components. Stateless functional components and class-based components. Functional components are functions that accept a single props object argument with data and return a React element. Take a look at this line of your code again:

<Route path="/openAbcd" component={() => (<abcdContainer caller="aaaaaaa" />)} />

You passed an arrow function () => (<abcdContainer caller="aaaaaaa" />) to your <Route> element which is an inline definition of a functional component that takes props as a parameter and returns a rendered React element, in this case this is your <abcdContainer>. But as you can see you omitted the props parameter in your function by defining it with empty parenthesis: () => (<AComponent />). React does not automatically pass props to child components that are rendered inside a functional component. When wrapping your <abcdContainer> into an inline functional component you are responsible for passing props to it yourself.

But if you pass the class/variable of your class-based/functional component to the component prop of your <Route> element like you did it in your other routes then it will render this component an implicitly pass props to it because it isn't wrapped in a functional component:

// this will directly render <aContainer> and pass the props to it
<Route path="/" component={aContainer}>

What you did is creating a "functional unnamed wrapper component" that doesn't take any props and also doesn't pass any props further down.

And note that you should not use withRouter() extensively. This HOC is only there to inject a router into components that do not get rendered by a matching route itself and are e.g. much deeper down your component tree. In your case you do not need it.