1

From what I've read the pattern is the Components pass data to the Actions which Pass to the Store whose value changes trigger updates in Components that subscribe to the Stores. My question is how to "react" to these triggered updates in the form of a notification? ( ie a successfully saved notification )

Ie do I add logic to the render of this notification component that only displays itself if there is a some flag attribute in the object that its subscribed to? Then deletes itself after a time. This sounds wrong.

UPDATE

Thanks to Hannes Johansson I think I have a better grasp of a pattern. What I have working is the following:

  1. Component passes data through action to the Store

  2. The Store interacts with the api and adds a flag to the model that the component is now notified of an updated model.

    createItem: function (item) {
        $.ajax({
            url: '/items', 
            method: 'POST',
            data: item,
            success: function (item) {
                CurrentBrandActions.addCampaign(item);
                this.item = item;
                item.newlyCreated = true;
                this.trigger(item);
            }.bind(this)
        })
    }
    
  3. The Component sees the flag and renders a "Notification Child Component"

    var newlyCreated = this.state.item.newlyCreated === true;
    if (newlyCreated) {
      newlyCreated = <ItemCreatedNotification item={this.state.item} />
    } else {
      newlyCreated = '';
    }
    return (
      <form onSubmit={this.createItem} className="form">
        {newlyCreated}
    
  4. Something needs to move the app to a new place based on this event. Should this be a) the Notification Child Component b) Parent Component c) The Store?

According to Colin Megill's talk on flux api patterns the api interaction should occur in the Action, but reflux doesn't really allow for that.

UPDATE 2

  1. Component passes data to an Action called createItemRequest

  2. The Action has a preEmit hook that actually does the api call. The createItemRequest continues to the Store so that the store can change the model to reflect the state of sending which is then displayed in the component( maybe show a spinner ). The Action is also responsible for firing two other events depending on the api result.

    ItemActions.createItemRequest.preEmit = function (data) {
        $.ajax({
            url: '/items', 
            method: 'POST',
            data: data,
            success: function (item) {
                ItemActions.itemCreatedSuccess(item);
            },
            error: function (error) {
                ItemActions.itemCreatedError(error);
            }
        });
    }
    
Dan Baker
  • 1,757
  • 3
  • 21
  • 36
  • Regarding your update, I'm unsure what you mean when you say "move the app to a new pace". Do you mean you want to redirect to another route/page? Or do you mean that you need to eventually stop displaying the notification, after some elapsed time? – Hannes Johansson Jul 22 '15 at 18:17
  • Another thing to note is that a principle in Flux is that you never directly mutate state in the store as a response to some async operation such as an ajax callback, like you do in your example. Rather, you trigger yet another action (like createItemCompleted for example), and then your store also listens to *that* action and mutate the store there. In Reflux you can use the `preEmit` hook which is an option to `createAction` to accomplish what Colin's talking about. – Hannes Johansson Jul 22 '15 at 18:22
  • First Question: Yes redirect to a new page. Second Comment: I think I get what you mean about separating each intention to change state into its own action. Just to be clear about the `preEmit` hook. When does it resolve? Is the Actions then responsible to fire a different Action if the api call fails? – Dan Baker Jul 22 '15 at 18:53
  • Yes, you're doing it correctly in your second update, although you automatically get a "success" and a "failed" child action if you set `asyncResult` to true for the action, as explained in the Reflux docs in the section about async actions. Regarding route transitions, I would definitely not do it from the store (that should just contain logic for app data state imo), but from which component to do it is really up to you. I think the parent sounds like something I'd choose. – Hannes Johansson Jul 22 '15 at 19:53

1 Answers1

3

There are different approaches to this. For example, in Reflux it's very easy to listen directly to actions if you choose to, since each action is actually a "dispatcher".

However, the general, purist Flux principle is that only stores register with the dispatcher and that components only listen to store updates. And the store just trigger an event that notifies that something has changed, not providing any payload. Then it's up to the component to read the store's state and determine how to render it.

One approach would be the one you describe, put some flag on the items in the store to signal that an update has happened, but it would violate the Flux principle if the components themselves then update the stored items' flags, since only stores are meant to mutate state, and only in response to actions and not from any other source. So in that case the "Flux thing" to do would probably be to trigger yet another event that signals that the newly added item has been noted so that the store can then reset the flag in response to that action.

Another approach I can think of would be to diff the state in your component when it gets notified of a store update. Then keep the flags only in the component, or even keeping newly added items in a separate list in the state and render them separately.

There are no hard rules here, except that if you want to follow the core Flux principle, components should never directly mutate stores' state, because that should only be mutated by the stores themselves in response to actions. That allows for a uni-directional data flow and a single source of truth about the data, which is the main goal of Flux.

Hannes Johansson
  • 1,794
  • 2
  • 15
  • 28