Как я могу получить ownProps, используя reselect on redux?

Я хочу создать селектор с memoization, используя reselect, основанный на некоторых ownProps mapStateToProps.

Ответ 1

Вы можете сделать это, подключив селектор к компоненту, используя метод connect предоставленный обработчиком реакции-редукта, затем передайте компонентные реквизиты (ownProps) в качестве второго аргумента в селектор.

container.js

import { connect } from 'react-redux';
import { getVisibleTodos } from './selectors';

...

const mapStateToProps = (state, props) => {
  return {
    todos: getVisibleTodos(state, props),
  };
};

const VisibleTodoList = connect(
  mapStateToProps,
)(TodoList);

export default VisibleTodoList;

Затем вы можете получить доступ к этим реквизитам в своем селекторе

selectors.js

import { createSelector } from 'reselect';

const getVisibilityFilter = (state, props) =>
  state.todoLists[props.listId].visibilityFilter;

const getTodos = (state, props) =>
  state.todoLists[props.listId].todos;

const getVisibleTodos = createSelector(
  ...
);

export default getVisibleTodos;

Тем не менее, это не будет memoize правильно, если у вас есть несколько экземпляров компонента, из которого вы передаете реквизиты. В этом случае селектор будет каждый раз получать разные аргументы props, поэтому он всегда будет перепрограммировать, а не возвращать кешированное значение.

Чтобы разделить селектор по нескольким компонентам при передаче в реквизитах и сохранении memoization, каждому экземпляру компонента нужна собственная личная копия селектора.

Вы можете сделать это, создав функцию, которая возвращает новую копию селектора при каждом ее вызове.

selectors.js

import { createSelector } from 'reselect';

const getVisibilityFilter = (state, props) =>
  state.todoLists[props.listId].visibilityFilter;

const getTodos = (state, props) =>
  state.todoLists[props.listId].todos;

const makeGetVisibleTodos = () => {
  return createSelector(
    ...
  );
}

export default makeGetVisibleTodos;

Если аргумент mapStateToProps предоставленный для подключения, возвращает функцию вместо объекта, он будет использоваться для создания отдельной функции mapStateToProps для каждого экземпляра контейнера.

Имея это в виду, вы можете создать функцию makeMapStateToProps которая создает новый селектор getVisibleTodos, и возвращает функцию mapStateToProps которая имеет эксклюзивный доступ к новому селектору:

import { connect } from 'react-redux';
import { makeGetVisibleTodos } from './selectors';

...

const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos();
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props),
    };
  };
  return mapStateToProps;
};

const VisibleTodoList = connect(
  makeMapStateToProps,
)(TodoList);

export default VisibleTodoList;

Теперь каждый экземпляр контейнера VisibleTodosList получит свою собственную функцию mapStateToProps с помощью getVisibleTodos селектора getVisibleTodos. Memoization теперь будет работать правильно, независимо от порядка отображения контейнеров.


Это было адаптировано (явно скопировано) из документации Reselect