Введение

Прошло много времени с тех пор, как я написал свое первое приложение Redux. В то время я был очень взволнован этой новой архитектурой, и теперь я действительно считаю, что Redux — это лучший шаблон архитектуры внешнего интерфейса, который когда-либо существовал, я даже рассматриваю возможность использования того же шаблона в серверной части, используя Node. моего приложения после прочтения некоторых статей о DDD и других подходах к разработке программного обеспечения на стороне сервера. Меня так раздражала шумиха вокруг React и Angular, и я надеялся, что что-то другое появится из ниоткуда и спасет нас всех от всего этого маркетинга Google и Facebook…

Введите Редукс…

Redux великолепен, вы должны бороться против своей воли, чтобы делать все, используя этот шаблон. Самое замечательное в этом то, что это всего лишь шаблон. Нет необходимости использовать какие-либо рамки, и это просто. Мне очень нравится все, что гениально и просто одновременно.

Эта архитектура побуждает меня мыслить нестандартно, в этом смысле она меня очень вдохновляет. Если вы еще не знакомы с Redux, вам определенно стоит его попробовать... Все о нем можно найти на странице документации и в отличном скринкасте на egghead, сделанном Дэном Абрамовым, создателем Redux.

Немного критического взгляда

Несмотря на любовь к Redux, вы должны быть зрелыми… вы должны разделять вещи, чтобы не ослепнуть и не стать проповедником. У всего, что вам нравится, есть недостатки, и это осознание поможет вам сделать лучший выбор в некоторых ситуациях, когда недостатки могут быть более вредными.

С учетом сказанного, давайте перейдем к моим мыслям после моего опыта использования Redux.

  1. Конечно, Redux не предназначен для использования во всех приложениях, но есть некоторые приложения, которые остаются в середине поля сложности, слишком далеко от краев… Они не такие сложные и не такие простые. С моей точки зрения, для этих случаев Redux кажется слишком сложным.
  2. Другое дело, что у каждого редьюсера есть свой каскад switch case, и в некоторых ситуациях трудно представить, какой редьюсер отвечает на действие. Вы должны открыть файл каждого редуктора, чтобы определить, к каким действиям они на самом деле прикреплены.
  3. Состав редюсера иногда может быть немного сложным для понимания.
  4. В некоторых случаях вы хотели бы, чтобы взаимосвязь действий и редукторов была более прямой.

Настройка логики 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, и он работал как шарм, он функциональный, простой и в то же время понятный. Я очень довольна результатом и, честно говоря, не ожидала, что это сработает так хорошо.

Пока =)