Ответ 1
Сделав эту ошибку самостоятельно (не с Redux, но с аналогичной внутренней инфраструктурой Flux), проблема в том, что ваш предлагаемый подход связывает селекторов с местоположением связанного состояния редуктора в общем дереве состояний. Это вызывает проблему в нескольких случаях:
- Вы хотите иметь редуктор в нескольких местах в дереве состояний (например, поскольку связанный компонент отображается в нескольких частях экрана или используется несколькими независимыми экранами вашего приложения).
- Вы хотите повторно использовать редуктор в другом приложении, а структура состояния этого приложения отличается от вашего исходного приложения.
Он также добавляет неявную зависимость от вашего корневого редуктора к каждому селектору модуля (поскольку они должны знать, к какому ключу они находятся, что на самом деле является ответственностью корневого редуктора).
Если селектор нуждается в состоянии от нескольких разных редукторов, проблему можно увеличить. В идеале модуль должен просто экспортировать чистую функцию, которая преобразует срез состояния в требуемое значение, и до файлов корневого модуля приложения, чтобы подключить его.
Один хороший трюк состоит в том, чтобы иметь файл, который экспортирует только селектор, все принимают срез состояния. Таким образом, они могут обрабатываться в пакете:
// in file rootselectors.js
import * as todoSelectors from 'todos/selectors';
//...
// something like this:
export const todo = shiftSelectors(state => state.todos, todoSelectors);
(shiftSelectors имеет простую реализацию - я подозреваю, что библиотека повторного выбора уже имеет подходящую функцию).
Это также дает вам имя-интервал - все селекторные переключатели доступны под экспортом todo. Теперь, если у вас есть два списка todo, вы можете легко экспортировать todo1 и todo2 и даже предоставлять доступ к динамическим, экспортируя memoized функцию для их создания для определенного индекса или идентификатора, скажем. (например, если вы можете отображать произвольный набор списков todo за раз). Например.
export const todo = memoize(id => shiftSelectors(state => state.todos[id], todoSelectors));
// but be careful if there are lot of ids!
Иногда селекторам требуется состояние из нескольких частей приложения. Опять же, избегайте проводки, кроме корня. В вашем модуле у вас будет:
export function selectSomeState(todos, user) {...}
а затем файл корневых селекторов может импортировать это и повторно экспортировать версию, которая соединяет "todos" и "user" с соответствующими частями дерева состояний.
Итак, для небольшого, отложенного приложения оно, вероятно, не очень полезно и просто добавляет шаблон (особенно в JavaScript, который не является самым кратким функциональным языком). Для большого набора приложений, в котором используется множество общих компонентов, он позволяет многократно использовать его, и он сохраняет обязанности четко. Он также упрощает селекторов на уровне модулей, так как им не нужно сначала перейти на соответствующий уровень. Кроме того, если вы добавляете FlowType или TypeScript, вы избегаете действительно плохой проблемы, когда все ваши подмодули должны зависеть от вашего типа состояния корня (в основном, явная зависимость, о которой я упоминал, становится явной).