javascript - Idiomatic way to lazy-load with mobx -


what current idiomatic way lazy load properties when using mobx?

i've been struggling few days, , haven't found examples since strict mode has become thing. idea of strict mode, i'm starting think lazy-loading @ odds (accessing, or observing property should trigger side effect of loading data if it's not there).

that's crux of question, see how got here keep reading.

the basics of current setup (without posting ton of code):

react component 1 (listview): componentwillmount

  1. componentwillmount & componentwillreceiveprops - component gets filter values route params (react-router), saves observable object on listview, , tells store fetch 'proposals' based on it
  2. store.fetchproposals checks see if request has been made (requests stored in observablemap, keys serializing filter object 2 identical filters return same response object). makes request if needs , returns observable response object contains info on whether request finished or has errors.
    1. listview saves observable response object property can display loading or error indicator.
    2. listview has computed property calls store.getproposals using same filter object used fetch
    3. store.getproposals transformer takes filter object, gets proposals observablemap (keys on proposal.id), filters list using filter object , returns proposal[] (empty if nothing matched filter, including if no proposals loaded yet)

this appears work well.

the problem proposals have properties client , clientid. proposal.clientid string that's loaded proposal. want wait until client accessed tell store fetch server (assuming it's not in store). in case listview happens display client name, should loaded shortly after proposal is.

my closest i've gotten setting autorun in proposal's constructor list this, part of not reacting i'm indending. (truncated relevant sections):

@observable private clientid: string = ''; @observable private clientfilter: iclientfilter = null; @observable client: client = null;  constructor(sourcejson?: any) {     super(sourcejson);     if (sourcejson) {         this.mapfromjson(sourcejson);     }     //this 1 works. i'm turning clientid string object getclients transformer      autorun(() => { runinaction(() => { this.clientfilter = { id: this.clientid }; }) });     autorun(() => {         runinaction(() => {             if (this.clientid && this.clientfilter) {                 const clients = datastore.getclients(this.clientfilter);                 const response = datastore.fetchclients(this.clientfilter);                 if (response.finishedtime !== null && !response.haserrors) {                     this.client = clients[0] || null;                     console.log('this never called, should see client here: %o', datastore.getclients(this.clientfilter));                 }             }         })     }); } 

the response object observable:

export class queryrequest<t extends persistentitem | enum> {     @observable starttime: date = new date();     @observable finishedtime: date = null;     @observable errors: (string | error)[] = [];     @observable items: t[] = [];     @computed haserrors() { return this.errors.length > 0; }     @observable usedcache: boolean = false; } 

i'm getting feeling i'm fighting system, , setting autoruns in constructor doesn't seem ideal anyway. solve pattern in reasonable way? i'm open suggestions on whole thing if setup looks crazy.


edit 1: removed @mobx clarity.


edit 2: trying re-evaluate situation, (again) found excellent lib mobx-utils, has lazyobservable function may suite needs. it's looking this:

client = lazyobservable((sink) => {     autorun('lazy fetching client', () => {         if (this.clientfilter && this.clientfilter.id) {             const request = datastore.fetchclients(this.clientfilter);             if (request.finishedtime !== null && !request.haserrors) {                 sink(request.items[0]);             }         }     }) }, null); 

this working!

i think need autorun in there update based on objects clientid/clientfilter property (if object later assigned new client i'd want lazyobservable updated). don't mind little boilerplate lazy properties, i'm, open suggestions there.

if ends being way go i'll looking @ frompromise same lib instead of observable request object. not sure because i'm keeping track of start time check staleness. linking here in case else has not come across it:)

i've been using different approach in projects , extracted separate npm package: https://github.com/mdebbar/mobx-cache

here's quick example:

first, need react component display client info:

@observer class clientview extends react.component {   render() {     const entry = clientcache.get(this.props.clientid)      if (entry.status !== 'success') {       // return kind of loading indicator here.       return <div>still loading client...</div>     }      const clientinfo = entry.value     // can render ui based on clientinfo.     return (       <div>         <h2>{clientinfo.name}</h2>       </div>     )   } } 

then, need setup clientcache:

import mobxcache "mobx-cache";  function fetchclient(id) {   // use fetching mechanism like. make sure return promise. }  const clientcache = new mobxcache(fetchclient) 

that's need do. mobxcache automatically call fetchclient(id) when it's needed , cache data you.


Comments

Popular posts from this blog

java - Jasper subreport showing only one entry from the JSON data source when embedded in the Title band -

mapreduce - Resource manager does not transit to active state from standby -

serialization - Convert Any type in scala to Array[Byte] and back -