Search code examples
javascriptreactjsreactjs-fluxalt.js

Listen for a specific Store property change


I have a Component which initial state is set to be equal to a Store state. Also the Component is subsribed to any change that occurs in the Store.

// Inital component's state is set to be equal to a Store state
constructor(props) {
    super(props);
    this.state = EntityStore.getState();
    this.entitiesOnChange = this.entitiesOnChange.bind(this);
}

// Subscribe to any Store's change
componentDidMount() {
    EntityStore.listen(this.entitiesOnChange);
}

// Update the state with the new one
entitiesOnChange(nextState) {
    this.setState(nextState);
}

My goal is to subscribe the Component to a specific property of the Store.

I tried to make a check in entitiesOnChange, but I find out that this.state is already up to date with the Store's state (nextState). Also in the following code example (what I tried) this.setState(nextState) isn't called, because the both states are equal, therefore rerendering doesn't occur:

// Update the state with the new one only if a specefic `propery` is changed
entitiesOnChange(nextState) {
    // Here is the problem. `this.state` is already up to date.
    if (this.state.property !== nextState.property) {
        this.setState(nextState);
    }
}

So how can I subscribe my Component to a specific Store's property?


Solution

  • Alright! I deeply investigated the problem and finaly I've find out what's happening. The problem was caused by a wrong way of setting the data in the store. It was mutated (which is wrong). The correct (flux) way is creating a new object.

    I've created a JSFiddle to illustrate the whole problem, but here are the highlights of the wrong mutation in the Store:

    class Store {
        constructor() {
            this.bindActions(actions);
            this.data = {
                items: [],
                isLoading: false
            };
        }
    
        set(items) {
            this.data.isLoading = true;
    
            // Simulate API call
            setTimeout(() => {
                this.data.items = items;
                this.data.isLoading = false;
                this.setState(this);
            }, 2000);
    
            this.setState(this);
        }
    }