Введение
Прошло много времени с тех пор, как я написал свое первое приложение Redux. В то время я был очень взволнован этой новой архитектурой, и теперь я действительно считаю, что Redux — это лучший шаблон архитектуры внешнего интерфейса, который когда-либо существовал, я даже рассматриваю возможность использования того же шаблона в серверной части, используя Node. моего приложения после прочтения некоторых статей о DDD и других подходах к разработке программного обеспечения на стороне сервера. Меня так раздражала шумиха вокруг React и Angular, и я надеялся, что что-то другое появится из ниоткуда и спасет нас всех от всего этого маркетинга Google и Facebook…
Введите Редукс…
Redux великолепен, вы должны бороться против своей воли, чтобы делать все, используя этот шаблон. Самое замечательное в этом то, что это всего лишь шаблон. Нет необходимости использовать какие-либо рамки, и это просто. Мне очень нравится все, что гениально и просто одновременно.
Эта архитектура побуждает меня мыслить нестандартно, в этом смысле она меня очень вдохновляет. Если вы еще не знакомы с Redux, вам определенно стоит его попробовать... Все о нем можно найти на странице документации и в отличном скринкасте на egghead, сделанном Дэном Абрамовым, создателем Redux.
Немного критического взгляда
Несмотря на любовь к Redux, вы должны быть зрелыми… вы должны разделять вещи, чтобы не ослепнуть и не стать проповедником. У всего, что вам нравится, есть недостатки, и это осознание поможет вам сделать лучший выбор в некоторых ситуациях, когда недостатки могут быть более вредными.
С учетом сказанного, давайте перейдем к моим мыслям после моего опыта использования Redux.
- Конечно, Redux не предназначен для использования во всех приложениях, но есть некоторые приложения, которые остаются в середине поля сложности, слишком далеко от краев… Они не такие сложные и не такие простые. С моей точки зрения, для этих случаев Redux кажется слишком сложным.
- Другое дело, что у каждого редьюсера есть свой каскад switch case, и в некоторых ситуациях трудно представить, какой редьюсер отвечает на действие. Вы должны открыть файл каждого редуктора, чтобы определить, к каким действиям они на самом деле прикреплены.
- Состав редюсера иногда может быть немного сложным для понимания.
- В некоторых случаях вы хотели бы, чтобы взаимосвязь действий и редукторов была более прямой.
Настройка логики Redux
В общем, Redux работает, изменяя свойства одного источника состояния, используя функции (редукторы), которые проверяют тип действия и реагируют или нет на изменение состояния с помощью свойств действия.
Чтобы решить пункт 1, я удалил создателей действия. Чтобы решить вопросы 3 и 4, я поместил функции редуктора в объект, у которого есть связанные проблемы. Например, для списка задач есть основной объект, содержащий «добавить», «удалить», «обновить»… редукторы.
Пункт 2 было немного трудно решить, потребовалось некоторое время, чтобы разобраться, потому что нужно было изменить основную структуру Redux. Таким образом, ответ состоял в том, чтобы инвертировать шаблон Redux.
Инвертирование редукса
В Redux невозможно иметь 2 разных типа действий с одинаковыми именами, поэтому мы можем сохранить эти типы действий как методы Store, используя один и тот же стандарт верхнего регистра с подчеркиванием в качестве разделителя:
let store = new Store({ selected :null, items :[] }) store.FETCH = ( state, action )=>{ http({ url :action.url }).then( ( data ) => store.dispatch({ action:’LOADED’, data })) return state } store.LOADED = ( state, action )=>{ state.items = reducer.update( state.items, action ) return state } store.SELECT = ( state, action )=>{ action.items = state.items state.selected = reducer.select( state.selected, action ) return state }
Таким образом, я могу легко увидеть каждое действие и какой редуктор отвечает на действие. Визуально лучше… При таком подходе свойства хранилища получают полное состояние хранилища и отправленное действие. Методы .subscribe() и .publish() не изменились, вызовы остались прежними.
Я понял, что эти изменения позволяют мне соединить два разных состояния, как вы можете видеть в типе действия «ВЫБРАТЬ». Использовать Redux не так просто, вам нужно найти способ решить эту проблему, и поверьте мне, вы будете часто сталкиваться с такой проблемой, даже в простом приложении Todo.
В перевернутом Redux я могу выбрать элемент в своем приложении без необходимости отправлять весь список в вызове публикации:
store.publish({ action: 'SELECT', id: 5 })
Я не проводил каких-либо тестов, но я действительно считаю, что это также быстрее, потому что в Redux каждое действие публикации вызывает каждый отдельный редюсер и не проходит через его случаи переключения. Перевернутый Redux просто проверяет тип действия в объекте Store и вызывает этот метод, который содержит только редукторы, связанные с этим изменением.
Для приложения Todo у меня был бы объект, содержащий все редукторы, связанные со списком Todo, например:
export default{ add( state = [], action ){ state.push({ id: guid(), text :action.text }) }, remove( state = [], action ){ return state.filter( item => item.id != action.id ) }, update( state = [], action ){ let item = state.filter( item => item.id == action.id )[0] item.text = action.text return state }, select( state = [], action ){ let item = state.filter( item => item.id == action.id )[0] item.selected = true return state } }
Я также думаю, что весьма полезно получать состояние Store в качестве аргумента в обратных вызовах подписки вместо того, чтобы каждый раз вызывать .getState()…
store.subscribe( (state) => view.update( state ) )
Ну наконец то…
Как и Redux, Inverted Redux не предназначен для использования во всех приложениях. У него есть и недостатки, и, как и любое другое решение, его нужно использовать в правильной ситуации. Я протестировал его в большом приложении электронной коммерции, а также в некоторых мобильных приложениях HTML5, и он работал как шарм, он функциональный, простой и в то же время понятный. Я очень довольна результатом и, честно говоря, не ожидала, что это сработает так хорошо.
Пока =)