reflux / refluxjs

A simple library for uni-directional dataflow application architecture with React extensions inspired by Flux
BSD 3-Clause "New" or "Revised" License
5.36k stars 330 forks source link

Async/await pattern with async actions #536

Open rkpatel33 opened 6 years ago

rkpatel33 commented 6 years ago

I would like to use asyc/await instead of flux async actions with action.completed/action.failed child actions, but after staring at some of the issues related to async actions, I'm unsure how to proceeds. I've looked at this one in particular:

https://github.com/reflux/refluxjs/issues/524

The core of what I am trying to accomplish is to call two async actions aimed at to different stores, one after the other in a React component as follows:

// Inside some React class component

async componentDidMount() {
    // Aimed at the `ChannelQueueStore`
    await ChannelQueueActions.loadTickets(this.props.loggedInAgent);
    // Aimed at the `ChatStore`
    await ChatActions.updateChannel(this.state.selectedChannel);
  }

My ChannelQueueStore as currently implemented is defined below, and as written the above code does not work. ChatActions.updateChannel is triggered immediately after ChannelQueueActions.loadTickets instead of waiting.

I'm wondering if someone can suggest a way to refactor the below code so the above will work.

// Inside my `ChannelQueueStore` store
export default class ChannelQueueStore extends Reflux.Store {
  constructor() {
    super();
    this.state = {
      selectedChannel: null,
      channels: []
    };
    this.tw = new TwilioWrapper(); // Has a bunch of promise returning async functions
    this.listenTo(ChannelQueueActions.loadTickets, this.onLoadTickets);
  }

  async onLoadTickets(agentID) {
    // getOpenChannelsOwnedbyAgentSerialized is an `async` function, use await to wait until its done.
    let channels = await this.tw.getOpenChannelsOwnedbyAgentSerialized(agentID);

    this.setState({
      selectedChannel: channels[0].uniqueName,
      channels: channels
    });
  }
}

I could call ChatActions.updateChannel(this.state.selectedChannel) from at the end of onLoadTickets, which works but seems like bad form, and I think putting both action calls in the component itself makes it easier to see whats going on in the component.

Thx.

kra3 commented 6 years ago

What you are trying to achieve is what gaearon/redux-thunk or redux-saga/redux-saga does for redux. That is chain together asynchronous operations/side-effects.

Reflux way of achieving this is through child actions (with async enabled.) Have a look at the documentation at https://github.com/reflux/refluxjs/tree/master/docs/actions#asynchronous-loading-via-child-actions

rkpatel33 commented 6 years ago

Got it, thanks for the response!

songguangyu commented 6 years ago

image this demo is to easy, can provide a complete demo ?