Search code examples
reactjsreduxreact-router-dom

mapStateToProps react router dom v6 useParams()


BlogDetailsPage.js

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

const BlogDetailsPage = (props) => {
  const { id } = useParams();
  return <div>Blog Details: {}</div>;
};

const mapStateToProps = (state, props) => {
  const { id } = useParams();
  return {
    blog: state.blogs.find((blog) => {
      return blog.id === id;
    }),
  };
};

export default connect(mapStateToProps)(BlogDetailsPage);

How to use mapStateToProps in "useParams()" react-router-dom ?

and whatever links that navigate to /slug path are ended up in BlogDetailsPage.js, Since BlogDetailsPage.js is being nested nowhere else so i couldn't get specific props pass down but route params. From my perspective this is completely wrong but i couldn't figure out a better way to do it.

Compiled with problems:X

ERROR


src\components\BlogDetailsPage.js
  Line 11:18:  React Hook "useParams" is called in function "mapStateToProps" that is neither a React function component nor a custom React Hook function. React component names must start with an uppercase letter. React Hook names must start with the word "use"  react-hooks/rules-of-hooks

Search for the keywords to learn more about each error.```

Solution

  • Issue

    React hooks can only be called from React function components or custom React hooks. Here it is being called in a regular Javascript function that is neither a React component or custom hook.

    Solutions

    Preferred

    The preferred method would be to use the React hooks directly in the component. Instead of using the connect Higher Order Component use the useSelector hook to select/access the state.blogs array.

    Example:

    import { useSelector } from 'react-redux';
    import { useParams } from 'react-router-dom';
    
    const BlogDetailsPage = () => {
      const { id } = useParams();
      const blog = useSelector(state => state.blogs.find(
        blog => String(blog.id) === id
      ));
    
      return <div>Blog Details: {}</div>;
    };
    
    export default BlogDetailsPage;
    

    Alternative/Legacy

    If you have the need to access path params in any mapStateToProps function, if you are using a lot of oder code for example, then you'll need to create another HOC to access the path params and have them injected as props so they are available in the mapStateToProps function.

    Example:

    import { useParams, /* other hooks */ } from "react-router-dom";
    
    const withRouter = Component => props => {
      const params = useParams();
      // other hooks, useLocation, useNavigate, etc..
      return <Component {...props} {...{ params, /* other injected props */ }} />;
    };
    
    export default withRouter;
    

    ...

    import { compose } from 'redux';
    import { connect } from 'react-redux';
    import withRouter from '../path/to/withRouter';
    
    const BlogDetailsPage = ({ blog }) => {
      return <div>Blog Details: {}</div>;
    };
    
    const mapStateToProps = (state, { params }) => {
      const { id } = params || {};
      return {
        blog: state.blogs.find((blog) => {
          return String(blog.id) === id;
        }),
      };
    };
    
    export default compose(
      withRouter,              // <-- injects a params prop
      connect(mapStateToProps) // <-- props.params accessible
    )(BlogDetailsPage);