10

In my React/Redux app I am often facing with the problem of implementing components with state which should be used throughout the app. Let's take simple popup component as an example with open/close state which can be reused in any page. Here is two possible approaches I found:

  • Use setState and "local" reducer (I use recompose.withReducer which is just syntax sugar for React's native setState) to manage its state. It looks easy and reusable until you need change the component's state in the other part of your page (close popup in out case). And you cannot just call some redux action to change the state.

  • Keep the component's state in the Redux store. With such approach we can call closePopupAction({ id }) in any place of the components tree to change it's state.` But we need somehow put its reducer (which i want to keep in the popup's folder) to the root reducer when the component is mounted and delete it when the component is unmounted. Plus we can have multiples popups in the page and each of them have its own state.

Did anybody face with a similar problem ?

Eugene Gluhotorenko
  • 3,094
  • 2
  • 33
  • 52
  • I am not sure what you are asking. Are you asking which solution is better than the other one? – wuct Oct 04 '16 at 03:19
  • 1
    both ways don't work. So I am looking for something other – Eugene Gluhotorenko Oct 04 '16 at 11:23
  • Can you elaborate what do you want to achieve? I believe both ways are works. In `recompose` case, if you want to call `setState` in other subtrees, you can hoist `withState()` to higher node. In `redux` case, there is no need to remove reducers, unless the state is extremely large. – wuct Oct 19 '16 at 02:13
  • though it's 10m old, could you share what you came up with if anything? – Evgeny Timoshenko Aug 22 '17 at 11:57
  • I would feel so sad for end users, if there could be multiple popups on the page. Genuine problem otherwise. – Nishant Feb 22 '18 at 14:20

2 Answers2

1

I think you should keep state of component in redux. You can create reducer for this component and use combineReducers function in this way:

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

then when you call closePopupAction("id1") reducer can check id and change proper part of state.

PS: Id should be provided in better way :)

Piotr Labunski
  • 1,638
  • 4
  • 19
  • 26
  • 2
    Redux requires to specify exact structure of the state. But what if I have list of popups ? Each of them has each own state – Eugene Gluhotorenko Oct 14 '16 at 20:03
  • You have to set only initial state. There are 2 option: 1. const initialState = { popups: [] } Something similar you can see in that [todomvc example](https://github.com/reactjs/redux/tree/master/examples/todomvc) 2. const initialState = { popupsById: {} } and after action AddPopup(id, someState) in reducer state.popupsById[id] = someState objectAssign({}, state); – Piotr Labunski Oct 14 '16 at 21:57
  • This answer is a solution to a different problem. – Willem D'Haeseleer Nov 07 '16 at 23:22
  • 1
    Can you explain why? Question is about reusable react components in React/Redux app, in response I suggested that reusable components should also have reusable reducers and to combine reducers you can use combineReducers function. – Piotr Labunski Nov 08 '16 at 11:49
0

You could mount each component's state to its own slice of the store.

So your closePopupAction actions would be called with that mount path:

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

and you would need only one reducer to handle all closePopupAction actions, which could be registered once at startup:

 (state, { type, mountPath }) => {
      if (type === 'CLOSE_POPUP_ACTION') {
         // manipulate with the slice at `mountPath`, e.g.
         return _.set(_.cloneDeep(state), `${mountPath}.isOpen`, false)
      }
      // ...
   }
Evgeny Timoshenko
  • 3,119
  • 5
  • 33
  • 53