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.
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)