Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ReactJS Flux Utils components

There is interesting article which describes 4 main classes exposed in Flux Utils.

  1. Store
  2. ReduceStore
  3. MapStore (removed from 3.0.0)
  4. Container

But it's not super clear what should be used for certain situations. There are only 2 examples for ReduceStore and Container, but no samples for others unfortunately.

Could you please explain basic usage for these 4 components: when and where they should be used in real life?

Extended answers and code examples would be really appreciated!

UPDATE:

MapStore has been removed starting from 3.0.0

like image 259
oleh.meleshko Avatar asked Jan 28 '16 20:01

oleh.meleshko


People also ask

What are components of flux?

Flux applications have three major parts: the dispatcher, the stores, and the views (React components). These should not be confused with Model-View-Controller.

How do you use flux in React JS?

js and copy-paste the following code: import { Dispatcher } from "flux"; const dispatcher = new Dispatcher(); export default dispatcher; Here we are importing the Dispatcher from the flux library that we installed, creating a new object and exporting it so that our actions module can use it.

What is flux in React JS?

What is flux. Flux is a pattern for managing how data flows through a React application. As we've seen, the preferred method of working with React components is through passing data from one parent component to it's children components. The Flux pattern makes this model the default method for handling data.

What is the primary advantage of using flux implementation in React?

Main Features of Flux Flux keeps code predictable when compared to other MVC frameworks. Developers can build applications without being bothered about complicated interactions between data resources. Flux boasts of a better structured data flow – unidirectional. Being unidirectional is the central feature of Flux.


1 Answers

By poking through the code and reading through the method documentation, here's what I can work out (I have not used these classes myself, as I use other Flux frameworks).

It's actually useful to go in almost reverse order for these.

Container

This is not a subclass of FluxStore because it is, unsurprisingly, not a store. The Container is a wrapper class for your React UI components that automatically pulls state from specified stores.

For example, if I have a React-driven chat app with a component that lists all my logged-in friends, I probably want to have it pull state from a LoggedInUsersStore, which would hypothetically be an array of these users.

My component would look something like this (derived from the code example they provide):

import {Component} from 'react';
import {Container} from 'flux/utils';

import {LoggedInUsersStore} from /* somewhere */;
import {UserListUI} from /* somewhere */;

class UserListContainer extends Component {
  static getStores() {
    return [UsersStore];
  }

  static calculateState(prevState) {
    return {
      loggedInUsers: LoggedInUsersStore.getState(),
    };
  }

  render() {
    return <UserListUI counter={this.state.counter} />;
  }
}

const container = Container.create(UserListContainer);

This wrapper automatically updates the component's state if its registered stores change state, and it does so efficiently by ignoring any other changes (i.e. it assumes that the component does not depend on other parts of the application state).

I believe this is a fairly direct extension of Facebook's React coding principles, in which every bit of UI lives in a high-level "Container." Hence the name.

When to use

  • If a given React component is entirely dependent on the state of a few explicit stores.
  • If it does not depend on props from above. Containers cannot accept props.

ReduceStore

A ReduceStore is a store based entirely on pure functions---functions that are deterministic on their inputs (so the same function always returns the same thing for the same input) and produce no observable side effects (so they don't affect other parts of the code).

For example, the lambda (a) => { return a * a; } is pure: it is deterministic and has no side effects. (a) => { echo a; return a; } is impure: it has a side effect (printing a). (a) => { return Math.random(); } is impure: it is nondeterministic.

The goal with a ReduceStore is simplification: by making your store is pure, you can make certain assumptions. Because the reductions are deterministic, anyone can perform the reductions at any time and get the same result, so sending a stream of actions is all but identical to sending raw data. Likewise, sending the raw data is perfectly reasonable because you were guaranteed no side effects: if my entire program is made of ReduceStores, and I overwrite the state of one client with the state of another (calling the required redraws), I am guaranteed perfect functionality. Nothing in my program can change because of the actions rather than the data.

Anyway, a ReduceStore should only implement the methods explicitly listed in its documentation. getInitialState() should determine the initial state, reduce(state, action) should transform state given action (and not use this at all: that would be non-deterministic/have side effects), and getState() & areEqual(one,two) should handle separating the raw state from the returned state (so that the user can't accidentally modify it).

For example, a counter would be a sensible ReduceStore:

class TodoStore extends ReduceStore {
    getInitialState() {
        return 0;
    }

    reduce(state, action) {
        switch(action.type) {
            case 'increment':
                return state + 1;
            case 'decrement':
                return state - 1;
            case 'reset':
                return 0;
            default:
                return state;
    }

    getState() {
        // return `this._state`, which is that one number, in a way that doesn't let the user modify it through something like `store.getState() = 5`
        // my offhand JS knowledge doens't let me answer that with certainty, but maybe:
        var a = this._state + 1;
        return a - 1;
    }
}

Notice that none of the transforms explicitly depended on the current state of the object: they only operated on the state variable they were passed. This means that an instance of store can calculate state for another instance of the same store. Not so useful in the current implementation of FB Flux, but still.

When to use

  • If you like pure-functional programming (yay!)
  • and if you don't like it enough to use a framework explicitly built with that assumption (redux, NuclearJS)
  • and you can sensibly write a store that is purely-functional (most stores can, and if they can't it might make sense to think about architecture a little more)

Note: this class does not ensure that your code is purely-functional. My guess is that it will break if you don't check that yourself.

I would always use this store. Unless I could use a...

FluxMapStore [DEPRECATED]

This class is no longer part of Flux!

This is a subclass of ReduceStore. It is for such pure-functional stores that happen to be Maps internally. Specifically, Immutable.JS maps (another FB thing!).

They have convenience methods to get keys and values from the state:

WarrantiesStore.at('extended') rather than WarrantiesStore.getState().get('extended').

When to use

  • As above, but also
  • if I can represent this store using a Map.

FluxStore

This brings us to FluxStore: the catch-all Store class and generic implementation of the Flux Store concept.

The other two stores are its descendants.

The documentation seems to me to be fairly clear on its usage, so I'll leave it at that

When to use

  • If you cannot use the other two Store util classes to hold your data
  • and you don't want to roll your own store

In my case, that would be never: I prefer immutable frameworks like redux and NuclearJS because they are easier for me to reason about. I take care to structure my stores in a purely functional way. But if you don't, this class is good.

like image 119
citelao Avatar answered Oct 24 '22 18:10

citelao