erikras / react-redux-universal-hot-example

A starter boilerplate for a universal webapp using express, react, redux, webpack, and react-transform
MIT License
12.01k stars 2.5k forks source link

Connect to multiple different actions and different states #735

Open manuelmazzuola opened 8 years ago

manuelmazzuola commented 8 years ago

Hello, maybe an example is more helpful than the title.

I've a statistics module and an info module. Each module has the load method and the [LOAD, LOAD_SUCCESS, LOAD_FAIL] action types. Of course LOAD in statistics module is redux-example/statistics/LOAD and LOAD in info module is redux-example/info/LOAD Each module have the following switch:

switch (action.type) {
    case LOAD:
      return {
        ...state,
        loading: true
      }

Now, how can I listen for all the redux-example/ALL MODULES/LOAD action type and get the array of state.ALL MODULES.loading properties ?

manuelmazzuola commented 8 years ago

So I can show a progress bar if at least one of the loading properties is true.

Dattaya commented 8 years ago

@manuelmazzuola, one simple way I can think of is to create another module and on every page load reset the count:

switch (action.type) {
  case info.LOAD:
  case statistics.LOAD:
    return state.numLoading + 1;

  case info.LOAD_SUCCESS:
  case info.LOAD_FAILURE:  
  case statistics.LOAD_SUCCESS:  
  case statistics.LOAD_FAILURE:  
    return state.numLoading - 1;
}

Then when the numLoading has reached 0, remove the progress bar. Maybe you can automate this through a custom redux middleware?

Dattaya commented 8 years ago

In addition, I've seen this: https://github.com/tappleby/redux-batched-subscribe but haven't used it myself. It might be possible to adapt it to work with actions with side effects.

Dattaya commented 8 years ago

I guess those two were bad ideas and you can just do this return Promise.all([dispatch(load1()), dispatch(load2())]).then(dispatch(disableProgressBar()) in your fetching decorator.

trueter commented 8 years ago

Is dispatching both actions at the same time really what you want? Consider merging them to tell Actions more user-centric than functionaliy-centric. if you want to make separate API calls you can probably still use Promise.all in the action creator. When it comes to determining loading state you could just set each store to loading on its own and inside your component's connect decorator define a combined loading prop.

@connect( state => {
  // ..
  return {
    // ..
    loading: state.statistics.loading || state.info.loading
  }
}, actions )
export default class MyTwoStoreComponent extends React.Component {
  render ( 
    <span>{ ( this.props.loading ? 'Some' : 'No'  ) + ' store is loading' </span>
  )
}