6
import books from '../books'


function BookScreen({ match }) {
    const book = books.find((b) => b._id === match.params.id)
    return (
        <div>
            {book}
        </div>
    )
}

export default BookScreen

I keep getting the error match is undefined. I saw a tutorial with similar code, but it seemed fine when put to the test. Any clue what might be the issue?

2 Answers2

13

If match prop is undefined this could be from a few things.

react-router-dom v5

If using RRDv5 if the match prop is undefined this means that BookScreen isn't receiving the route props that are injected when a component is rendered on the Route component's component prop, or the render or children prop functions. Note that using children the route will match and render regardless, see route render methods for details.

Ensure that one of the following is implemented to access the match object:

  1. Render BookScreen on the component prop of a Route

    <Route path="...." component={BookScreen} />
    
  2. Render BookScreen on the render or children prop function of a Route and pass the route props through

    <Route path="...." render={props => <BookScreen {...props} />} />
    

    or

    <Route path="...." children={props => <BookScreen {...props} />} />
    
  3. Decorate BookScreen with the withRouter Higher Order Component to have the route props injected

    import { withRouter } from 'react-router-dom';
    
    function BookScreen = ({ match }) {
      const book = books.find((b) => b._id === match.params.id)
      return (
        <div>
          {book}
        </div>
      );
    };
    
    export default withRouter(BookScreen);
    
  4. Since BookScreen is a React function component, import and use the useParams hook to access the route match params

    import { useParams } from 'react-router-dom';
    
    ...
    
    function BookScreen() {
      const { id } = useParams();
      const book = books.find((b) => b._id === id)
      return (
        <div>
          {book}
        </div>
      );
    }
    

react-router-dom v6

If using RRDv6 then there is no match prop. Gone are the route props. Here only the useParams and other hooks exist, so use them.

import { useParams } from 'react-router-dom';

...

function BookScreen() {
  const { id } = useParams();
  const book = books.find((b) => b._id === id)
  return (
    <div>
      {book}
    </div>
  );
}

If you've other class components and you're using RRDv6 and you don't want to convert them to function components, then you'll need to create a custom withRouter component. See my answer here with details.

Drew Reese
  • 165,259
  • 14
  • 153
  • 181
-1

I guess you rendered BookScreen component before match is initialized. This is why match is undefined when BookScreen rendered. Render it conditionally like below.

return (
  ... other components
 {match && <BookScreen match={match}/>}

)

Also, I leave useful site which tells you some good ways to do that. :D

https://www.digitalocean.com/community/tutorials/7-ways-to-implement-conditional-rendering-in-react-applications

I hope you find an answer :D

Dae Hyeon Mun
  • 521
  • 4
  • 7