How to access match inside mapStatetoProps

Viewed 48

How can I access match prop inside mapStateToProps?

import React from "react";
import "./collectionpage.styles.scss";
import { connect } from "react-redux";
import { selectCollection } from "../../redux/shop/shop.selector";
import { useMatch } from "react-router-dom";
import Collectionitem from
  "../../components/collection-items/Collectionitem.component";
   
const CollectionPage = ({ collection }) => {
  const match = useMatch();
  const { title, items } = collection;

  return (
    <div className="collection-page">
      <h2 className="title">{title}</h2>
      <div className="items">
        {items.map(item => <Collectionitem key={item.id} item={item}/>)}
      </div>
    </div>
  )
}

mapStatetoProps = (state) => {
  return ({
    collection: selectCollection(match.params.colletionID)(state)
  })
} 

export default connect(mapStatetoProps)(CollectionPage);
2 Answers

mapStatetoProps allow you pass owner props to. So you can pass match to a component. in this case is CollectionPage

const ComponentA = () => {
    const match = useMatch();
    return (<CollectionPage match={match}/>)
}

then:

const mapStateToProps = (state, ownProps) => {
      return {
       collection: ownProps.match.params.colletionID
      }
 }

react-router-dom@5

Since it appears you are using react-router-dom@5 you'll have the withRouter Higher Order Component (HOC) available to you which can inject the route props. I've often combined this with the connect HOC to first wrap and inject the route props so they are accessible within the connect HOC.

Example:

import { connect } from "react-redux";
import { selectCollection } from "../../redux/shop/shop.selector";
import { withRouter } from "react-router-dom";

const CollectionPage = ({ collection }) => {
  ....
}

mapStateToProps = (state, props) => ({
  collection: selectCollection(props.match.params.colletionID)(state),
}); 

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

Since you are also using Redux you may also find the compose function very handy here to compose all the HOCs over the component you want to decorate. It serves as a way to "unnest" all the HOCs your components may be using

Example:

import { compose } from 'redux';
import { connect } from "react-redux";
import { selectCollection } from "../../redux/shop/shop.selector";
import { withRouter } from "react-router-dom";

const CollectionPage = ({ collection }) => {
  ....
}

mapStateToProps = (state, props) => ({
  collection: selectCollection(props.match.params.colletionID)(state),
}); 

export default compose(
  withRouter,
  connect(mapStateToProps),
)(CollectionPage);

react-router-dom@6

If using react-router-dom@6 you'll need to create your own custom withRouter replacement since it was removed in v6.

Example:

import { useParams, /* other hooks */ } from 'react-router-dom';

const withRouter = WrappedComponent => props => {
  const params = useParams();
  // etc... other react-router-dom v6 hooks

  return (
    <WrappedComponent
      {...props}
      params={params}
      // etc...
    />
  );
};

...

import { compose } from 'redux';
import { connect } from "react-redux";
import { selectCollection } from "../../redux/shop/shop.selector";
import { withRouter } from "../path/to/withRouter";

const CollectionPage = ({ collection }) => {
  ....
}

mapStateToProps = (state, props) => ({
  collection: selectCollection(props.params.colletionID)(state),
}); 

export default compose(
  withRouter,
  connect(mapStateToProps),
)(CollectionPage);
Related