New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Where to put store helper methods? #252

Closed
davidscolgan opened this Issue Feb 21, 2015 · 6 comments

Comments

Projects
None yet
4 participants
@davidscolgan

davidscolgan commented Feb 21, 2015

Hello!

Is there a good place to put code that operates on the data sent out from a store when the store calls its trigger method? For example, suppose I have a store for holding a person's first and last name:

userStore = Reflux.createStore({
    init: function() {
        this.user = {
            firstName: "",
            lastName: ""
        };

        this.listenTo(newDataLoaded, 'onNewDataLoaded');
    }

    onNewDataLoaded: function(data) {
        this.user.firstName = data.firstName;
        this.user.lastName = data.lastName;
        this.trigger(this.user);
    }
});

When new data is loaded, the store will send out the first name and last name via the trigger method.

Now suppose in my component I wanted to get the user's full name. If I was only doing this in one place, I could just concatenate the first and last name together in the component, but if I was doing that in many different places, it'd be nice to have a getFullName() method somewhere. This would be especially true if the example was more complicated than just concatenating the values together; suppose a complex transform of the data had to happen before it was usable.

My first instinct is to put getFullName() on the store:

getFullName: function() {
    return this.user.firstName + ' ' + this.user.lastName;
}

And then a component would directly call that, but from trying to understand Reflux style, it appears that the only way stores transmit data to components is via the trigger method.

Would you put this getFullName method on the component (but then what if you want to use it elsewhere?), on the store (but then the component calls methods directly on the store), or perhaps have it as a standalone function floating around in a util module somewhere (but the method only really makes sense in the context of the store).

@davidscolgan

This comment has been minimized.

davidscolgan commented Feb 21, 2015

I did see that the Reflux component mixin has a connectFilter method, but this still doesn't allow the code to be used in more than one place.

@srph

This comment has been minimized.

Contributor

srph commented Feb 21, 2015

It technically allows the code to be used in more than one place.

// YoloStoreUtil.js
var Reflux = require('reflux');
module.exports = {
  fullName: Reflux.connectFilter(....);
};

// YourComponent.jsx
var fullNameFilterMixin = require('./YoloStoreUtil').fullName;

React.createClass({
  mixins: [fullNameFilterMixin],
});
@dmwyatt

This comment has been minimized.

dmwyatt commented Feb 21, 2015

Someone please correct me if this is a discouraged style, but when you say:

the only way stores transmit data to components is via the trigger method

I'd say transmitting data is different from retrieving data. Stores do transmit data with the trigger method, but what you're talking about is a component retrieving data, and in that case I think it makes perfect sense to have a getFullName method on the store.

The store is supposed to contain your data and business logic.

Note that I've only been using refluxjs for a week, so I'd love for @spoike or someone with more experience using refluxjs to step in with their input.

@davidscolgan

This comment has been minimized.

davidscolgan commented Feb 21, 2015

Aha, that would make sense. From what I've seen in the examples, stores seem to usually only contain a single array or object that contains actual data, and that data is transmitted in its entirety when trigger is called. I don't suppose there's a reason not to still wire up components to listen to that trigger and receive that data, but also make other getter methods of the store available?

I did find some other Flux-like libraries that use this style, but in those, whenever the store notifies components of a change, it doesn't transmit any data, it only notifies. The components then use getters on the store to get whatever data they needed.

@dmwyatt

This comment has been minimized.

dmwyatt commented Feb 22, 2015

Right, that's my thought on the matter.

If you can get the data you need from a trigger, get it. If you need other data or the data processed in some way expose a method.

@spoike spoike added the question label Feb 24, 2015

@spoike

This comment has been minimized.

Member

spoike commented Feb 24, 2015

trigger passes the arguments over to the listeners... and I personally prefer to pass all the data that the components need through the event. I have passed the store itself (for quick prototype hacks) and use setters and getters. Both approaches are equal valid implementations and I don't want to enforce one over the other.

However I don't personally encourage the latter approach (of setters and getters on the store) since that usually has been a slipper slope to create stores that are "god classes". "God class" or "big ball of mud" are anti-patterns that I like to avoid.

As to how to reuse, I use mixins when applicable. If you think about them as traits, it makes it easy to attach functionality that you may want to reuse. If you need to add common methods to all stores you may add them to the Reflux.StoreMixin which is used during creation of stores.

@spoike spoike closed this Jul 11, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment