react-router v4 - How to provide params to a pure function using "component" attribute

1.2k views Asked by At

I have the following code:

const CatalogContainer = () => (
    <Match
      pattern="/catalog/:id"
      exactly
      render={({ params }) => (
        <Redirect to={`/catalog/${params.id}/titles`} />
      )}
    />
)

But ESLint is throwing the following warning due to the =>, which is (AFAIK) a bad practice because it creates a new references of the render function at every call and I don't want that.

warning JSX props should not use arrow functions react/jsx-no-bind

So, I'm trying to refactor this using a dedicated yet simple component like:

const DefaultRedirect = (params) => (
  <Redirect to={`/catalog/${params.id}/titles`} />
);

But, I'm having a hard time figuring out how to use it.

Firstly, I think I need to use component instead of render attribute, but I'm not quite sure and I haven't found the right documentation about it so far. (Edit: https://react-router.now.sh/Match Here is the doc for v4)

I tried several things, including the following, but it doesn't work.

<Match
  pattern="/catalog/:id"
  exactly
  component={DefaultRedirect({ params })}
/>

I found a few examples but all of them are using React.createClass, which I would rather not use since using const appear to be the new "best" way to do things for stateless components.


One possible solution is to use a Class that extends React.Component. But it feels wrong. (And ESLint is showing errors about it)

Component should be written as a pure function react/prefer-stateless-function

class DefaultRedirect extends React.Component {
  render() {
    const { params } = this.props;
    return (
      <Redirect to={`/catalog/${params.businessMid}/titles`} />
    );
  }
}

From the doc about the render method: (https://react-router.now.sh/Match)

Instead of having a component rendered for you, you can pass in a function to be called when the location matches. Your render function will be called with the same props that are passed to the component. This allows for convenient inline match rendering and wrapping.

Maybe convenient, but not considered as a good practice though.

Is there a way to do that using a pure function instead?

2

There are 2 answers

0
jamesism On BEST ANSWER

looks like you're close but not quite.

First, your dedicated functional component should parse params out of props like so:

const DefaultRedirect = ({ params }) => (
  <Redirect to={`/catalog/${params.id}/titles`} />
);

* Note the destructuring in the function arguments.

Second, when you pass the component to Match just pass the reference, like so:

<Match
  pattern="/catalog/:id"
  exactly
  component={DefaultRedirect}
/>

Hope this helps!

0
Paul S On

Disclaimer React Router v4 is still in alpha and its API is still in flux. Any advice here may become moot depending on the direction that v4 goes.

Each component rendered by a <Match> has a few props that are provided to it. These are location, pattern, params, isExact, and pathname. The last three are only provided when the pattern matches the current location.pathname.

For a component that will be rendered for a <Match>, you can destructure the params prop out of the props passed to it.

const DefaultRedirect = ({ params }) => (
  <Redirect to={`/catalog/${params.id}/titles`} />
);

You can just pass that component to the <Match> then.

<Match
  pattern="/catalog/:id"
  exactly
  component={DefaultRedirect}
/>