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

Multiple Instances of the same Store #505

Closed harsimranb closed 7 years ago

harsimranb commented 7 years ago

I looked through the documentation and could not figure out a way to do this. Essentially, I am building a modular plugin system, in which I am hoping to have one Reflux store per PluginComponent. However, it's possible that there can be multiple PluginComponents on the page that share the same store, as shown below.

class PluginStore extends Reflux.Store {
     constructor(pluginId) {
     }
}

In the component:

class PluginFrame extends Reflux.Component {
     constructor() {
          ...
         this.store = new PluginStore(pluginId);
     }
}

Is this possible with this library at the moment? I've looked at a few others and haven't found one that achieves this.

BryanGrezeszak commented 7 years ago

Yes. Multiple ways actually.

For one, it's actually perfectly possible to instantiate Reflux store classes and assign the instance to this.store in the component.

However, that limits you in a few ways. Mainly that global state (which relies on tracking each singleton of a store) will not work.

So instead, I would recommend creating a factory for the store class. Here's a fully functioning example:

var MyActions = Reflux.createActions(['increment']);

// THIS is the important part! The function returns a completely new class on each call.
function myStoreFactory(id, start)
{
    class MyStore extends Reflux.Store
    {
        constructor() {
            super();
            this.listenables = MyActions;
            this.state = {count:start};
        }

        onIncrement() {
            this.setState({count:this.state.count+1});
        }
    }

    MyStore.id = id;

    return MyStore;
}

class MyComponent1 extends Reflux.Component
{
    constructor(props) {
        super(props);
        this.store = myStoreFactory('store1', 10);
    }

    render() {
        return <div>count: {this.state.count}</div>;
    }
}

class MyComponent2 extends Reflux.Component
{
    constructor(props) {
        super(props);
        this.store = myStoreFactory('store2', 20);
    }

    render() {
        return <div>count: {this.state.count}</div>
    }
}

class Root extends React.Component
{
    constructor(props) {
        super(props);
    }

    render() {
        return (
            <div>
                <MyComponent1 />
                <MyComponent2 />
            </div>
        )
    }
}

This preserves basically every normal functionality, since you're actually making a new class every time myStoreFactory is called. So if you check the global state, it's all tracking just fine.

harsimranb commented 7 years ago

@BryanGrezeszak Thanks for the quick response. That is awesome, totally forgot about using a factory. My only other question is can I cache the Stores for the same ID, since I want to reuse those . Something like:

var myStores = [];
function myStoreFactory(id, start)
{
    if(myStores[id]) { 
        return myStores[id];
    }
    class MyStore extends Reflux.Store
    {
        constructor() {
            super();
            this.listenables = MyActions;
            this.state = {count:start};
        }

        onIncrement() {
            this.setState({count:this.state.count+1});
        }
    }

    MyStore.id = id;
    myStores[id] = myStores;
    return MyStore;
}
BryanGrezeszak commented 7 years ago

Yeah. That would usually be an object, not an array, but the general gist is right.

Or: any store with an id gets stored at Reflux.stores anyway. So you could just check that.

harsimranb commented 7 years ago

@BryanGrezeszak Thanks, that's working awesome. Only thing is the Action is getting fired for both instances of the store. I am using the id which is getting stored in Reflux.stores.

BryanGrezeszak commented 7 years ago

I'm confused by what you mean. In flux you don't call actions for a store. If your store is listening for an an action and it is called, then it'll catch it. So yeah, it would be called for any store that is listening.

harsimranb commented 7 years ago

Yes, you are right. That is the expected behavior as per the flux architecture.