How to use a class model with Redux (with the Mobx option)

EDIT: I finally chose Mobx.js, refer to @mweststrate answer for details.

All training resources on reduction show how to use it in simple object models. But I can't figure out how to use it when you use some models of the es6 class.

For example, take this form of state:

{ players:{ 000:{ life:56, lvl:4, //... }, 023:{ life:5, lvl:49, //... }, 033:{ life:679, lvl:38, //... }, 067:{ life:560, lvl:22, //... }, //... } 

And this class (not verified)

 class Player{ id; //int life; //int lvl; //int buffs; //[objects] debuffs; //[objects] inventory; //[objects] _worldCollection; //this class know about the world they belongs to. constructor({WorldCollection}){ this._worldCollection = WorldCollection; } healPlayer(targetId, hp){ this._worldCollection.getPlayer(targetId).setHealth(hp); } // setter setHealth(hp){ this.life += hp; } } 

Suppose I have a collection of 100 WorldCollection players. What is the best way?

Take 1: copy all properties from the instance to the state tree

 { players:{ 001:{ life: 45, lvl: 4, buffs: [objects] debuffs:[objects] inventory:[objects] }, 034:{ life: 324, lvl: 22, buffs: [objects] debuffs:[objects] inventory:[objects] }, 065:{ life: 455, lvl: 45, buffs: [objects] debuffs:[objects] inventory:[objects] }, //... } 

This can be done by typing dispatch in the constructor.

 //... constructor({WorldCollection, dispatch}) //... 

Submit an action in each setter.

 // setter setHealth(hp){ this.life += hp; dispatch({type:"HEAL_PLAYER", data:{id:this.id}) } 

And put all the logic in the gearboxes (the setter logic will be deterministic and atomic).

 ... case "HEAL_PLAYER": return { ...state, life: state.life + action.hp }; ... 

Pro:

  • IMHO It seems to me that a more reductive way is to have only one place where the whole state is.

Minuses:

  • All logic is decentralized from the model elsewhere. I do not like to multiply files. But maybe this is not a problem?
  • Redux says that logic should be executed in actions, not reducers.
  • The state takes twice as much memory. I saw immutables.js can optimize this, but I'm not sure.

Take 2: save only identifiers in the state tree of reduction

 { players:[ 001, 002 //... ] } 

This can be done using dispatch in each setter and send an action after each setter

 // setter setHealth(hp){ this.life += hp; dispatch({type:"PLAYER_UPDATED", data:{id:this.id}) } 

When changing the new state of the tree. I call mapStateToProps and WorldCollection.getPlayer() to get the correct instance and map its properties to the view.

Pros:

  • Redux mode is respected without putting logic into gearboxes.
  • Not a "duplicate state" (if Immutables.js cannot optimize this)
  • Logic in the model (makes more sense to me)

Minuses:

  • Redux state does not represent a whole state

I hope I haven’t simplified the matter too much. I would like to clarify if / can use decux for some class models.

Take 3: use Mobx.js / with Redux instead

--- very preliminary experimental here ---

I discovered Mobx.js a week ago, and its simplicity / perfection had me.

I think we could observe each member of the class (which together forms the state of the application)

  @observable life; //int @observable lvl; //int @observable buffs; //[objects] @observable debuffs; //[objects] @observable inventory; //[objects] 

and somewhere else there is a class that builds a state tree, maybe Redux might make sense here? (Note: I don't know how to do this. Have to go deeper into Mobx)

These are the pros / cons in pure compaxison redux / mobx for my case .

Pros:

  • Less detailed
  • No model for inherited (e.g. in redux-orm)
  • Performance was rated (so I almost don't know where I would go)
  • Do not write “rated” gears in class models (just mutators)

Minuses:

  • I don't know how to implement redo / undo (or the jitter buffer in a gaming device).
  • It seems that this is not a “tree”, as in redux, so that the whole state is in blinking (for me, this is the function of the redux killer)
+8
javascript state redux mobx
source share
3 answers

You might want to look at redux-orm , which pretty much does it already. It provides a nice model façade over the actual data of a simple object in your Redux state and handles relational data very well.

+3
source share

I would like to add that if you are going to use Redux , you will not store state in classes at all . In Redux, this logic will be described in reducers that will work on simple objects, and not on class instances. You would save the data so that each object is stored on the map of the object by its identifier, and any link to child entities would be an array of identifiers, and not a real link. Then you wrote down selectors to restore the pieces of data that you need for rendering.

You may find this discussion helpful, as well as these two examples:

+8
source share

(author of MobX). For a short answer to questions about MobX:

Repeat / cancel can be implemented in two ways:

  • Use the action / dispatcher model from the stream: send serializable actions and interpret them to update the state model. Thus, you can create an additional only event log and undo / redo database.
  • Automatically serialize your state model into a state history (which uses structural sharing). The demo version of Jet 2015 demonstrates this beautifully: https://github.com/mobxjs/mobx-reactive2015-demo/blob/master/src/stores/time.js . During this serialization, you can also generate delta patches instead of a complete state tree if it is easier to handle.

Tree of one state:

  • MobX must also have one source of truth. The main difference from Redux is that it does not direct you to store it. And that does not force you to have a tree. Count will be fine too. Getting a snapshot of this graph can be simple using mobx.toJson or using the previous solution to reuse / cancel item 2.
  • To make sure everything is in the same connected graph (which you like), simply create root status objects that point to the player and the world collection (for example). But unlike Redux, you do not need to normalize from there. The world can simply have direct links to players and vice versa. The demo version of reactive 2015 also creates a single-user root object: https://github.com/mobxjs/mobx-reactive2015-demo/blob/master/src/stores/domain-state.js
+6
source share

All Articles