On React Flux, where I am supposed to populate the initial state of my Stores?
Asked Answered
X

4

5

I'm studying Flux and I think I understood the workflow:

View -> Action -> Dispatcher -> Store -> View

However, I didn't quite understand where am I supposed to populate the initial state of my Stores.

For instance, let's say that I'm editing a Contact. So I'd assume I'd have a ContactsStore. This is what I imagine would happen when I access the URL /contacts/edit/23:

  1. Somehow my ContactsStore gets populated with the contact I'm editing, in this case, contact 23. The data would come from the server.
  2. The EditContact view would receive a notification from the ContactsStore, so it would render itself in the initial state.
  3. As I save the contact, the view would trigger the SaveContact action and the flow would go on.

Step (1) is not clear to me. Where is the ContactsStore expected to be populated with the initial state? Where do I call the server? Is it on the Store?

Thanks.

Xerophilous answered 23/7, 2015 at 13:47 Comment(0)
H
5

You need to have access to the action and the store in your EditContact component. In the componentDidMount handler you could fire an action which does the api request. On success it passes the contact to the dispatcher/store. As soon as the store receives the contact it fires an event on which the EditContact component has subscribed. In the corresponding handler the component sets the new state with the new contact. I'm sure there are other ways to do this, but that's how I would do it.

Hautevienne answered 23/7, 2015 at 14:16 Comment(0)
K
3

The way I, and I think many others, do it is I trigger an action from the view to load the contact. Let's call it LOAD_CONTACT. This would be an asynchronous action. Some people put the API call in the store directly, but I think it's more common to do async work in the action creators. So let's say you have an action creator loadContactAction(). Then that would first dispatch the LOAD_CONTACT action (just in case some store might be interested in this, for displaying a "loading" message or something), then fetch from the API. In the callback of the ajax request, you call another action creator, e.g. loadContactSuccessAction() (or "failed", of course). Your ContactsStore store then registers and reacts to LOAD_CONTACT_SUCCESSFUL.

var loadContactAction = function(...) {
    // maybe do some work
    dispatch(...); // dispatch your LOAD_CONTACT action

    makeRequest(...).then(function(contact) {
        loadContactSuccessAction(contact); // create "success" action
    }, function(err) {
        loadContactFailedAction(err); // probably handle this somewhere
    });
}

var ContactsStore = {
    init(...) {
        // register in dispatcher here
    },
    onLoadContactSuccess(contact) {
        this.contacts[contact.id] = contact; // or store your contact some other way
        this.emitChange(); // trigger a store update change event with whatever event dispatcher you use
    }
}

var EditContact = React.createClass({
    componentDidMount: function() {
        ContactsStore.listen(this.onStoreChange);
        loadContactAction(); // pass in ID or however you want to load it
    },
    onStoreChange: function() {
        // fetch your contact here
    },
    render: function() {
        ...
    }
});
Kaput answered 23/7, 2015 at 14:16 Comment(0)
C
1

I agree with Florian Gl answer though i would recommend reading the article below, about higher order components, you should leave the logic out of your component, and use a higher order component that passed the data as props, avoid using state as much as possible , it will only add extra complexity

in Your higherlevel component(container): componentWillMount handler you can fire an action which does the api request, on success this state is saved to the store, and as soon as the store receives the contact it fires an event on which the EditContact component Container has subscribed -> which is passed to the editContact component

State should live in your store:)

https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750

Chatelaine answered 24/7, 2015 at 11:26 Comment(0)
W
0

When you're constructing the initial state of your app, you should fire an action to fetch the data for "contact 23". That action makes an asynchronous call, which results in an event, which populates a store, which a component uses to get its state.

However, do you want to put the logic that fires the action in that component? Not necessarily. Are you using any routing libraries? If so, they are likely the best place from which to trigger the action.

For example, using fluxible-router, its routing configuration allows you to specify that each route (e.g. /contacts/23) should fire an action.

This lets you decouple how to display data from how to retrieve it. You could use the same component and have it get its data from AJAX in one case, from local storage in another case, etc. You could also optimize the fetching of data, e.g. by bundling together multiple calls, without having to change any components.

Woodpecker answered 17/9, 2015 at 0:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.