Redux: Using withRouter() to Inject the Params into Connected Components

Share this video with your friends

Send Tweet

We will learn how to use withRouter() to inject params provided by React Router into connected components deep in the tree without passing them down all the way down as props.

-kaik-
-kaik-
~ 8 years ago

Hi!

I get an error retrieving filter params on the end component (props.params is null), as if "withRouter" was not working at all (however, props have a "router" property).

I'm getting same error with cloned code from your repo :(

-kaik-
-kaik-
~ 8 years ago

I've seen that the issue was related with the version of react-router.

However, trying to update package.json to use "react-router": "^3.0.0", throw an error with npm install.

I've solved it by using (in package.json) the last version available: "react-router": "^3.0.0-alpha.1"

ysfzrn
ysfzrn
~ 8 years ago

thanks kaik

Vicent Gozalbes
Vicent Gozalbes
~ 8 years ago

Hello, is it possible to use withRouter and retrieve the filter param without using connect? f.e here is how my code looks like:

import React, { Component, PropTypes } from 'react';
import { withRouter } from 'react-router';
import { toggleTodo } from '../actions';
import TodoList from './TodoList';

const getVisibleTodos = (todos, filter) => {
  switch (filter) {
    case 'completed':
      return todos.filter(t => t.completed);
    case 'active':
      return todos.filter(t => !t.completed);
    default:
      return todos;
  }
};

class VisibleTodoList extends Component {
  componentDidMount() {
    const { store } = this.context;
    this.unsubscribe = store.subscribe(() =>
      this.forceUpdate()
    );
  }

  componentWillUnmount() {
    this.unsubscribe();
  }

  render() {
    const { store } = this.context;
    const state = store.getState();

    // how can I access to `filter` router param?

    return (
      <TodoList
        todos={getVisibleTodos(
          state.todos,
          filter
        )}
        onTodoClick={id =>
          store.dispatch(toggleTodo(id))
        }
      />
    );
  }
}

VisibleTodoList.contextTypes = {
  store: React.PropTypes.object,
};

export default withRouter(VisibleTodoList);

Thanks!

mobility-team
mobility-team
~ 8 years ago

Thank you! The v4.0.0-alpha.3 should also work

kcrossfitter
kcrossfitter
~ 8 years ago

As indicated in the video, to use withRouter(), I have to use react-router version 3.0 or higher.

But there is a problem.

  • version 3.0.0 => No problem
  • version 3.0.1 => After selecting 'completed' or 'active', I cannot select 'all' again.
  • version 3.0.2 => After selecting 'completed' or 'active', I cannot select 'all' again.

Is this a bug in 3.0.1 or 3.0.2. How can I solve this issue?

Omri Mor
Omri Mor
~ 8 years ago

For those using Router v4, you will have to access the match object through the history object instead of directly. trying to access match directly from mapStateToProps would always throw undefined. See below:

const mapStateToProps = (state, history) => (
    {
        todos: getTodosByFilter(state.todos, history.match.params === undefined ? 'all' : history.match.params.filter)
    }
);```
Robert Smith
Robert Smith
~ 7 years ago

With RR4 you can also access the filter prop via match and destructure it in the function definition.

const mapStateToProps = (
  state,
  { match: { params: { filter } } }
) => ({
  todos: getVisibleTodos(state.todos, filter || 'all'),
});