How to show a loading indicator in React Redux app

2019-01-20 21:21发布

I'm new to React/Redux. I use a fetch api middleware in Redux app to process the APIs. It's https://github.com/agraboso/redux-api-middleware. I think it's the good way to process async api actions. But I find some cases which can't be resolve by myself.

As the homepage https://github.com/agraboso/redux-api-middleware#lifecycle say, a fetch API lifecycle begins with dispatching a CALL_API action ends with dispatching a FSA action.

So my first case is showing/hiding a preloader when fetching APIs. The middleware will dispatch a FSA action at the beginning and dispatch a FSA action at the end. Both the actions are received by reducers which should be only doing some normal data processing. No UI operations, no more operations. Maybe I should save the processing status in state then render them when store updating.

But how to do this? A react component flow over the whole page? what happen with store updating from other actions? I mean they are more like events than state!

Even a worse case, what should I do when I have to use the native confirm dialog or alert dialog in redux/react apps? Where should they be put, actions or reducers?

Best wishes! Wish for replying.

8条回答
一夜七次
2楼-- · 2019-01-20 21:51

We have three types of notifications in our app, all of which are designed as aspects:

  1. Loading indicator (modal or non-modal based on prop)
  2. Error Popup (modal)
  3. Notification snackbar (non-modal, self closing)

All three of these are at the top level of our app (Main), and wired through Redux as shown in the below code snippet. These props control display of their corresponding aspects.

I designed a proxy that handles all our API calls, thus all isFetching and (api) errors are mediated with actionCreators I import in the proxy. (As an aside, I also use webpack to inject a mock of the backing service for dev so we can work without server dependencies.)

Any other place in the app that needs to provide any type of notification simply imports the appropriate action. Snackbar & Error have params for messages to be displayed.

@connect(
// map state to props
state => ({
    isFetching      :state.main.get('isFetching'),   // ProgressIndicator
    notification    :state.main.get('notification'), // Snackbar
    error           :state.main.get('error')         // ErrorPopup
}),
// mapDispatchToProps
(dispatch) => { return {
    actions: bindActionCreators(actionCreators, dispatch)
}}

) export default class Main extends React.Component{

查看更多
太酷不给撩
3楼-- · 2019-01-20 21:56

Great answer Dan Abramov! Just want to add that I was doing more or less exactly that in one of my apps (keeping isFetching as a boolean) and ended up having to make it an integer (which ends up reading as the number of outstanding requests) to support multiple simultaneous requests.

with boolean:

request 1 starts -> spinner on -> request 2 starts -> request 1 ends -> spinner off -> request 2 ends

with integer:

request 1 starts -> spinner on -> request 2 starts -> request 1 ends -> request 2 ends -> spinner off

case REQUEST_POSTS:
  return Object.assign({}, state, {
    isFetching: state.isFetching + 1,
    didInvalidate: false
  })
case RECEIVE_POSTS:
  return Object.assign({}, state, {
    isFetching: state.isFetching - 1,
    didInvalidate: false,
    items: action.posts,
    lastUpdated: action.receivedAt
查看更多
登录 后发表回答