connected-react-router icon indicating copy to clipboard operation
connected-react-router copied to clipboard

How to access route params?

Open eladdo92 opened this issue 5 years ago • 14 comments

Hey, I'm having a hard time figuring out how to work with multiple sub-routers. I have two components that get called from deferent sub-routers but both rely on the same routepath. I want to use the redux-store to save the route parameters so I won't need to explicitly pass the props down to all children (I have many components down the tree), But I can't decide how and who is responsible to update this key in the store. What is the best way to model this kind of behaviour?

eladdo92 avatar Jul 15 '18 13:07 eladdo92

Does #85 answer your question?

CalMlynarczyk avatar Jul 24 '18 15:07 CalMlynarczyk

yes, thank you!

eladdo92 avatar Jul 25 '18 08:07 eladdo92

@CalMlynarczyk How does this work for more deeply nested components?

onionhammer avatar Jul 31 '18 13:07 onionhammer

@onionhammer If you are referring to other connected components, then I would expect the ownProps.match.params property still be there in the mapping function (although I have not verified this myself).

If you mean nested non-connected components, then you will simply have to pass the params that you need down to those components (or potentially use context).

CalMlynarczyk avatar Sep 08 '18 20:09 CalMlynarczyk

@eladdo92 Have you tried this:

import { createMatchSelector } from 'connected-react-router';

const matchSelector = createMatchSelector({ path: '/course/:id })
const match = matchSelector(state) // like: /course/123
const id = match.params.id; // get: 123

brneto avatar Oct 05 '18 00:10 brneto

@brneto This seems a bit ugly to have to repeat passing the path selector (Which should already be on the current route that we're on). I'm currently running into this issue now, where I need to access part of a path to convert to a selector.

danbopes avatar Nov 18 '18 10:11 danbopes

I created an HOC that adds the wanted params as props to the wrapped component. It also solves the dealing with update blocking when using connect. Hope it helps :)

`import React from 'react'; import { withRouter } from 'react-router'; import { matchPath } from 'react-router-dom'; import { connect } from 'react-redux'; import { createStructuredSelector } from 'reselect'; import pick from 'lodash/pick'; import { withProps, getDisplayName, compose } from 'recompose'; import hoistStatics from 'hoist-non-react-statics';

export function withRouteParams(...routeParams) { // why are we using connect here? // https://reacttraining.com/react-router/web/guides/dealing-with-update-blocking const withConnect = connect(createStructuredSelector({ pathname: state => state.getIn(['route', 'location', 'pathname']) }));

const withMatchParams = withProps(({ pathname, match }) => ({ ...pick(matchPath(pathname, match.path).params, routeParams) }));

return function WithRouteParams(WrappedComponent) { function RouteParams(props) { return <WrappedComponent {...props} />; }

RouteParams.displayName = `withRouteParams(${getDisplayName(WrappedComponent)})`;

hoistStatics(RouteParams, WrappedComponent);

return compose(
  withConnect,
  withRouter,
  withMatchParams,
)(RouteParams);

}; }`

Assuming MyComponent is under a path that includes a param called 'myParam': withRouteParams('myParam')(MyComponent)

eladdo92 avatar Nov 18 '18 11:11 eladdo92

@danbopes Actually, I centralize all routes in one file like:

// router.js
export const routes = {
  courses: { path: '/courses' },
  authors: { path: '/authors' },
  about: { path: '/about' },
  courseCreate: { path: '/course' },
  courseUpdate: { path: '/course/:id' },
  authorCreate: { path: '/author' },
  authorUpdate: { path: '/author/:id' }
};

and use it where I need. With that the code would become:

import { createMatchSelector } from 'connected-react-router';
import { routes } from './router.js';

const matchSelector = createMatchSelector(routes.courseUpdate)
const match = matchSelector(state) // like: /course/123
const id = match.params.id; // get: 123

brneto avatar Nov 18 '18 22:11 brneto

Hi, anyone has better and clean solutions for more deeply nested components?

joeyUOFA avatar Jun 05 '19 22:06 joeyUOFA

withRouter (from react-router) will allow you to access location, history and match on deeply nested components.

~https://reacttraining.com/react-router/web/api/withRouter~

https://v5.reactrouter.com/web/api/withRouter

EDIT: follow redirect

avindra avatar Jun 05 '19 23:06 avindra

Hi avindra,

I have a question. It works for component under this route. However my code has a Header component which is under a different switch. How can I access URL parameters under Header component? The match object is empty under Header component. Thanks.

joeyUOFA avatar Jun 06 '19 23:06 joeyUOFA

I have explained the situation in details in https://stackoverflow.com/questions/56486934/react-router-dom-match-object-isexact-false?noredirect=1#comment99563730_56486934

joeyUOFA avatar Jun 07 '19 02:06 joeyUOFA

It looks like there is no way to get params from thunk/saga

import { 
  withRouter
} from "react-router-dom";

Import the above in your component My case is Game . ( Not App.js component )

Then :

export default connect(mapStateToProps)( withRouter( Game ) );

componentDidMount() { 
    console.log(this.props)
  }

Cheers

vonmutinda avatar Jan 19 '20 10:01 vonmutinda