Повторно выберите несколько экземпляров памятки - PullRequest
0 голосов
/ 25 июня 2018

Я использую React / Redux / Reselect.

Из повторно выберите doc , если у меня есть несколько компонентов, которые будут использовать селектор с разными параметрами, мне нужно создать его для каждого экземпляра.

const makeGetVisibleTodos = () => {
  return createSelector(
    [ 
       (state, props) => props.visibilityFilter, 
       state => state.todos,
    ],
    (visibilityFilter, todos) => {
       return todos.filter(td => td.visibility === visibilityFilter)
      }
    }
  )
}

Но в моем случае listId может происходить из нескольких источников (например, props.listId, props.location.match.listId, props.location.search.listId и т. Д.)

Так что я чувствую себя болеенапример, написать следующее:

const makeGetVisibleTodos = listId => {
  return createSelector(
    [
      state => state.todos,
    ],
    (todos) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )
}

и подключить его следующим образом:

  connect(
    (state, ownProps) => ({
      offerer: makeGetVisibleTodos(ownProps.location.match.listId)(state, ownProps),
    }),
  )

Я почти уверен, что это работает, но я не уверен на 100%, что это запомнит правильно:

Если два компонента вызывают makeGetVisibleTodos с одинаковым listId, у них будет 2 разных значения кэша, верно?Что не то, что я хочу ...

Как насчет этого?

const makeGetVisibleTodos = listId => {
  return createSelector(
    state => state.todos,
    state => listId,
    (todos, listId) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )
}

В этом случае makeGetVisibleTodos(ownProps.listId) и makeGetVisibleTodos(ownProps.match.params.listId) совместно используют одно и то же значение кэша, когда ownProps.listId === ownProps.match.params.listId?

Или еще один способ сформулировать вопрос: как передать дополнительные параметры, которые (напрямую) не зависят от state и ownProps, но проверяются на равенство при запоминании?

Я мог бы также расширить ownProps:

  connect(
    (state, ownProps) => ({
      offerer: makeGetVisibleTodos()(state, Object.assign({}, ownProps, {listId: ownProps.location.match.listId}),
    }),
  )

Но нахожу это очень безобразным, и оно теряет смысл ...

Ответы [ 3 ]

0 голосов
/ 25 июня 2018

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

Обратите внимание на то, как в документации функция mapStateToPropsтакже становится заводской функцией (makeMapStateToProps), и makeGetVisibleTodos вызывается перед возвратом действительной функции mapStateToProps, например, так.

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

Кроме того, вы не пропускаете реквизиты, которые используете вваш селектор в вызове makeGetVisibleTodos(), но при фактическом вызове самого селектора.

Это приведет к чему-то вроде

const makeGetVisibleTodos = () => {
  return createSelector(
    state => state.todos,
    state => (_, listId), // Here you have access to all the arguments passed
    (todos, listId) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )
}

Затем вы можете написать селекторы так:

const makeMapStateToProps = () => {
  const getVisibleTodos = makeGetVisibleTodos()
  const mapStateToProps = (state, props) => {

    return {
      todos: getVisibleTodos(state, props.params.match.listId),
      todos2: getVisibleTodos(state, props.listId),
      todos3: getVisibleTodos(state, 'hardcodedListId')
    }
  }
  return mapStateToProps
}
0 голосов
/ 03 июля 2018

Как автор перевыбирает (небольшая оболочка вокруг reselect), я хотел бы указать, как библиотека решит ваш вариант использования.

re-reselect предоставляет селекторы, которые сохраняют памятку для разных компонентов из коробки.

import createCachedSelector from 're-reselect';

const getVisibleTodos = createCachedSelector(
  state => state.todos,
  (state, listId) => listId,
  (todos, listId) => {
     todos.filter(td => td.listId === listId)
    }
  }
)(
  (todos, listId) => listId, // Create/use a different selector for each different listId
);

Используйте его как обычный селектор (в любом другом компоненте контейнера) и забудьте о фабриках селекторов:

const makeMapStateToProps = () => {
  const mapStateToProps = (state, props) => {
    return {
      todos: getVisibleTodos(state, props.params.match.listId),
      todos2: getVisibleTodos(state, props.listId),
      todos3: getVisibleTodos(state, 'hardcodedListId')
    }
  }
  return mapStateToProps
}

Этот вариант использования также описан в повторный выбор документов .

0 голосов
/ 25 июня 2018

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

const listIdQuerySelector = (state, props) => {
    return props.match.params && props.match.params.listId;
};
const todoSelector = createSelector(
    [
      listIdQuerySelector,
      state => state.todos,
    ],
    (listId, todos) => {
       todos.filter(td => td.listId === listId)
      }
    }
  )

и использовать его как

connect(
    (state, ownProps) => ({
      offerer: makeGetVisibleTodos(state, ownProps),
    }),
  )
...