2

I recive a url param from useParams. I want to pass it to a selector using mapStateToProps.

collection.component.jsx

import { useParams } from "react-router-dom";
import { connect } from "react-redux";

import { selectShopCollection } from "../../redux/shop/shop.selectors";

import './collection.styles.scss'

const Collection = ({ collection }) => {
  const { collectionId } = useParams();
  console.log(collection)
  return (
    <div>
      <h1>{collection}</h1>
    </div>
  )
}

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

export default connect(mapStateToProps)(Collection);

shop.selectors.js

import { createSelector } from "reselect"

const selectShop = state => state.shop

export const selectShopCollections = createSelector([selectShop], shop =>
  shop.collections
)

export const selectShopCollection = collectionUrlParam =>
  createSelector([selectShopCollections], collections =>
    collections.find(collection => collection.id === collectionUrlParam)
  )

I guess the problem is that, I cannot pass params using match as react-router-dom v6 does not pass it in props. Is there any other way to pass collectionId to the selector selectShopCollection?

2 Answers2

5

Since Collection is a function component I suggest importing the useSelector hook from react-redux so you can pass the collectionId match param directly. It simplifies the component API. reselect selectors work well with the useSelector hook.

import { useParams } from "react-router-dom";
import { useSelector } from "react-redux";

import { selectShopCollection } from "../../redux/shop/shop.selectors";
import './collection.styles.scss'

const Collection = () => {
  const { collectionId } = useParams();
  const collection = useSelector(selectShopCollection(collectionId));

  console.log(collection);

  return (
    <div>
      <h1>{collection}</h1>
    </div>
  )
};

export default Collection;
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
0

Collection component can be given props by withRouter. But it was deprecated with react-router v6. Hence we need to create our own HOC which wrap our component. I created a HOC like this:

import { useParams } from "react-router-dom"

const withRouter = WrappedComponent => props => {
  const params = useParams()

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

export default withRouter;

See this answer for How to get parameter value from react-router-dom v6 in class to see why this HOC was made.

And, we can import the withRouter to the component and use with connect inside compose. Read more on compose. It just returns final function obtained by composing the given functions from right to left.

const mapStateToProps = (state, ownProps) => ({
  collection: selectShopCollection(ownProps.params.collectionId)(state)
})

export default compose(withRouter, connect(mapStateToProps))(Collection)