Skip to content
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

Composition #16

Closed
jesseskinner opened this issue Dec 3, 2015 · 1 comment
Closed

Composition #16

jesseskinner opened this issue Dec 3, 2015 · 1 comment

Comments

@jesseskinner
Copy link
Owner

It's always been challenging to combine multiple stores. The only way we could this achieve this is by adding a bunch of subscribers to each store, and then triggering actions on the main store to combine the data. I have an idea for a feature that could be built into Hoverboard to make this much easier.

For example, let's say you have a game.

var scoreStore = Hoverboard({
    init: function (state, initialScore) {
        return initialScore;
    },
    add: function (state, score) {
        return state + score;
    }
});

var healthStore = Hoverboard({
    init: function (state, initialHealth) {
        return initialHealth;
    },
    hit: function (state, amount) {
        return state - amount;
    }
});

You might want to combine these stores into a single GameStore for your game.

Currently, you'd have to do this:

var gameStore = Hoverboard({
    setScore: function (state, score) {
        return { score: score };
    },
    setHealth: function (state, health) {
        return { health: health };
    }
});

// subscribe to both stores
healthStore.getState(function (health) {
    gameStore.setHealth(health);
});
scoreStore.getState(function (score) {
    gameStore.setScore(score);
});

So this works, but what I'd like to do is make it easier to combined/compose different stores into a single store. Here's what I'm thinking:

var gameStore = Hoverboard.compose({
    score: scoreStore,
    health: healthStore
});

That's much simpler to understand and to write, and I think it'd make life much easier using Hoverboard.

Some other notes:

  • You should be able to pass in an array of stores, an object of stores, a single store (which would just be proxied through), or a static value, and have it set the state permanently of the store.
  • Only stores that are the immediate members of an object should be subscribed to. But you should be able to use Hoverboard.compose inside your object to do nested structures, eg.:
var gameStore = Hoverboard.compose({
    score: scoreStore,
    character: Hoverboard.compose({
        health: healthStore
    })
});
  • You should also be able to pass in arbitrary functions and basically receive a setState function to use with promises or callbacks for async purposes:
var asyncStore = Hoverboard.compose({
    user: function (setState) {
        loadUserFromServer(function (error, user) {
            setState(user);
        });
    }
});
@jesseskinner
Copy link
Owner Author

While looking at a way to simplify the TodoMVC example application, I came up with a slight addition to Hoverboard.compose that'll make this much more powerful.

What if you could pass any number of "translate" functions to Hoverboard.compose after the first argument, and have them translate or map the state automatically?

For example, in TodoMVC, I have a TodoStore for all the todos, and then I created an ActiveStore and CompletedStore which contain only the active/completed todos. Here's how I currently have to achieve this:

// create a simple store definition that allows setting a single list property
var ListStore = {
    list: function (state, list) {
        return { list: list };
    }
};

// create stores to contain the active and completed todos
var ActiveStore = Hoverboard(ListStore);
var CompletedStore = Hoverboard(ListStore);

TodoStore.getState(function (state) {
    var all = state.list;

    // when the TodoStore changes, set the lists in these two stores with filtered lists
    ActiveStore.list(_.filter(all, { completed: false }));
    CompletedStore.list(_.filter(all, { completed: true }));
});

Unfortunately, the new Hoverboard.compose does nothing to make this easier. So what if we could just do this instead?

// create stores to contain the active and completed todos
var ActiveStore = Hoverboard.compose(TodoStore, function (state) {
    return {
        list: _.filter(state.list, { completed: false })
    };
});

var CompletedStore = Hoverboard.compose(TodoStore, function (state) {
    return {
        list: _.filter(state.list, { completed: true })
    };
});

This would be incredibly powerful, especially combined with the rest of Hoverboard.compose's functionality. It'd create a reactive approach to Flux, so you could have data flow from any number of sources, and be mapped and translated into the shape you need.

Another great thing, it'll only need a couple extra lines of code added to Hoverboard.compose.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant