Многоразовые компоненты контейнера react-redux

В моем приложении React/Redux я часто сталкиваюсь с проблемой реализации компонентов с состоянием, которое должно использоваться во всем приложении. В качестве примера возьмем простой всплывающий компонент с открытым/закрытым состоянием, который можно повторно использовать на любой странице. Вот два возможных подхода, которые я нашел:

  • Используйте setState и «локальный» редуктор (я использую recompose.withReducer который является просто синтаксическим сахаром для собственного setState) React для управления его состоянием. Он выглядит простым и пригодным для повторного использования, пока вам не понадобится изменить состояние компонента в другой части вашей страницы (в противном случае закройте всплывающее окно). И вы не можете просто вызвать какое-то избыточное действие, чтобы изменить состояние.

  • Сохраняйте состояние компонента в магазине Redux. При таком подходе мы можем вызвать closePopupAction({ id }) в любом месте дерева компонентов, чтобы изменить его состояние. Но нам нужно как-то поместить его редьюсер (который я хочу сохранить в папке всплывающего окна) в корневой редюсер, когда компонент смонтирован, и удалить его. когда компонент размонтирован. Кроме того, у нас может быть несколько всплывающих окон на странице, и у каждого из них будет свое состояние.

Кто-нибудь сталкивался с подобной проблемой?


person Eugene Gluhotorenko    schedule 01.10.2016    source источник
comment
Я не уверен, что вы спрашиваете. Вы спрашиваете, какое решение лучше другого?   -  person wuct    schedule 04.10.2016
comment
оба пути не работают. Поэтому я ищу что-то другое   -  person Eugene Gluhotorenko    schedule 04.10.2016
comment
Можете ли вы уточнить, чего вы хотите достичь? Я считаю, что оба способа работают. В случае recompose, если вы хотите вызвать setState в других поддеревьях, вы можете поднять withState() на более высокий узел. В случае redux нет необходимости удалять редукторы, если только состояние не очень большое.   -  person wuct    schedule 19.10.2016
comment
хотя ему 10 м, не могли бы вы поделиться тем, что вы придумали, если что?   -  person Evgeny Timoshenko    schedule 22.08.2017
comment
Мне было бы очень грустно за конечных пользователей, если бы на странице могло быть несколько всплывающих окон. Истинная проблема иначе.   -  person Nishant    schedule 22.02.2018


Ответы (2)


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

rootReducer = combineReducers({
    moduleA: combineReducers({
      popupA: popupReducer("id1"),
      popupB: popupReducer("id2")
    }),
    moduleB: combineReducers({
      popupA: popupReducer("id3")
    })
  })
});

затем, когда вы вызываете closePopupAction ("id1"), редуктор может проверить идентификатор и изменить соответствующую часть состояния.

PS: Id должен быть предоставлен лучше :)

person Piotr Labunski    schedule 14.10.2016
comment
Redux требует указать точную структуру состояния. Но что, если у меня есть список всплывающих окон? У каждого из них есть свое состояние - person Eugene Gluhotorenko; 14.10.2016
comment
Вы должны установить только начальное состояние. Есть 2 варианта: 1. const initialState = { popups: [] } Нечто подобное вы можете увидеть в этом пример todomvc 2. const initialState = { popupsById: {} } и после действия AddPopup(id, someState) в редукторе state.popupsById[id] = someState objectAssign({}, state); - person Piotr Labunski; 15.10.2016
comment
Этот ответ является решением другой проблемы. - person Willem D'Haeseleer; 08.11.2016
comment
Можете ли вы объяснить, почему? Вопрос касается многократно используемых компонентов реакции в приложении React/Redux. В ответ я предложил, чтобы повторно используемые компоненты также имели многоразовые редукторы, а для объединения редукторов вы можете использовать функцию combReducers. - person Piotr Labunski; 08.11.2016

Вы можете смонтировать состояние каждого компонента в свой собственный фрагмент хранилища.

Таким образом, ваши действия closePopupAction будут вызываться с этим путем монтирования:

closePopupAction({ mountPath: 'popups.popup1' })

и вам понадобится только один редьюсер для обработки всех closePopupAction действий, которые можно зарегистрировать один раз при запуске:

 (state, { type, mountPath }) => {
      if (type === 'CLOSE_POPUP_ACTION') {
         // manipulate with the slice at `mountPath`, e.g.
         return _.set(_.cloneDeep(state), `${mountPath}.isOpen`, false)
      }
      // ...
   }
person Evgeny Timoshenko    schedule 22.08.2017