supasate / connected-react-router

A Redux binding for React Router v4
MIT License
4.73k stars 593 forks source link

How to access route params? #97

Open eladdo92 opened 6 years ago

eladdo92 commented 6 years ago

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?

CalMlynarczyk commented 6 years ago

Does #85 answer your question?

eladdo92 commented 6 years ago

yes, thank you!

onionhammer commented 6 years ago

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

CalMlynarczyk commented 6 years ago

@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).

brneto commented 6 years ago

@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
danbopes commented 5 years ago

@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.

eladdo92 commented 5 years ago

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)

brneto commented 5 years ago

@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
joeyUOFA commented 5 years ago

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

avindra commented 5 years ago

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

joeyUOFA commented 5 years ago

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 commented 5 years ago

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

pshkurateniuk-griddynamics commented 5 years ago

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

vonmutinda commented 4 years ago
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