1

私は自分の反応アプリをできるだけ乾燥させようとしています。残りのAPIを消費するなどの一般的なことのために、定義済みのアクションを持つストアとして機能するクラスを作成して、簡単に変更できるようにしました。

見よ、大きなコード:

import {autorun, action, observable} from 'mobx'

export function getResourceMethods(name) {
  let lname = name.toLowerCase()
  let obj = {
    methods: {
      plural: (lname + 's'),
      add: ('add' + name),
      addPlural: ('add' + name + 's'),
      rename: ('rename' + name),
    },
    refMethods: {
      add: ('add' + name + 'ByRef'),
      addPlural: ('add' + name + 'sByRef'),
      rename: ('rename' + name + 'ByRef'),
      setRef: ('set' + name + 'Ref'),
    },
    fetchMethods: {
      pending: (lname + 'Pending'),
      fulfilled: (lname + 'Fulfilled'),
      rejected: (lname + 'Rejected'),
    }
  }
  return obj
}

class ResourceItem {
  @observable data;
  @observable fetched = false;
  @observable stats = 'pending';
  @observable error = null;

  constructor(data) {
    this.data = data;
  }
}

class ResourceList {
  @observable items = [];
  @observable fetched = false;
  @observable status = 'pending';

  constructor(name) {
    this['add' + name + 's'] = action((items) => {
      items.forEach((item, iterator) => {
        this.items.push(item.id)
      })
    })
  }
}

class ResourceStore {
  constructor(name, resourceItem, middleware) {
    let {methods} = getResourceMethods(name)

    this.middleware = middleware || []

    let items = methods.plural.toLowerCase()
    this[items] = observable({}) // <--------------- THIS DOES NOT WORK!

    // Add resource item
    this[methods.add] = action((id, resource) => {
      let item = this[items][id], data;

      if (item && item.fetched) {
        data = item.data
      } else {
        data = resource || {}
      }

      this[items][id] = new resourceItem(data)
      this.runMiddleware(this[items][id])
    })

    // Add several resource items
    this[methods.addPlural] = action((resources) => {
      resources.forEach((resource, iterator) => {
        this[methods.add](resource.id, resource)
      })
    })

    // Rename resource item
    this[methods.rename] = action((oldId, newId) => {
      let item = this[items][oldId]
      this[items][newId] = item

      if (oldId !== newId) {
        delete this[items][oldId]
      }
    })
    // Constructor ends here
  }

  runMiddleware(item) {
    let result = item;
    this.middleware.map(fn => {
      result = fn(item)
    })

    return result
  }
}

class ReferencedResourceStore extends ResourceStore {
  @observable references = {}
  constructor(name, resource, middleware) {
    super(name, resource, middleware)

    let {methods, refMethods, fetchMethods} = getResourceMethods(name)

    let getReference = (reference) => {
      return this.references[reference] || reference
    }

    this[refMethods.setRef] = action((ref, id) => {
      this.references[ref] = id
    })

    this[refMethods.add] = action((ref, data) => {
      this[methods.add](getReference(ref), data)
      this[refMethods.setRef](ref, getReference(ref))
    })

    this[refMethods.rename] = action((ref, id) => {
      this[methods.rename](getReference(ref), id)
      this[refMethods.setRef](ref, id)
    })

    // *** Fetch *** //

    // Resource pending

    this[fetchMethods.pending] = action((ref) => {
      this[refMethods.add](ref)
    })

    // Resource fulfilled

    this[fetchMethods.fulfilled] = action((ref, data) => {
      this[refMethods.add](ref, data)
      this[refMethods.rename](ref, data.id)

      let item = this[methods.plural][data.id];
      item.fetched = true
      item.status = 'fulfilled'
    })

  }
}

export {ResourceItem, ResourceList, ResourceStore, ReferencedResourceStore}

今、私は単純なユーザーストアを作成しています:

class UserResource extends ResourceItem {
  constructor(data) {
    super(data)
  }

  @observable posts = new ResourceList('Posts')
  @observable comments = new ResourceList('Comment')
}

// Create store
class UserStore extends ReferencedResourceStore {}
let store = new UserStore('User', UserResource)

またmobx-react、ストアに問題なく接続し、それを読み取ることもできます。usersしかし、項目 (この場合、プロパティの名前は動的) プロパティに変更を加えるたびに、反応はありません。また、クロムでは、オブジェクト プロパティのツリー ビューに「invoke プロパティ ゲッター」がないことにも気付きました。

ここに画像の説明を入力

4

3 に答える 3

2

要点全体を読んだわけではありませんが、既存のオブジェクトで新しい監視可能なプロパティを宣言する場合は、ボックス化された監視可能オブジェクトのみを作成するため、現在監視可能な値はありますが、extendObservableまだ監視可能なプロパティはありません。言い換えると:observable

this[items] = observable({}) // <--------------- THIS DOES NOT WORK!

次のようにする必要があります。

extendObservable(this, {
  [items] : {}
})

上記の ES6 構文を使用できない場合は、次のように脱糖します。

const newProps = {}
newProps[items] = {}
extendObservable(this, newProps)

これを理解するには: https://mobxjs.github.io/mobx/best/react.html

編集:おっと、読み間違えました。すでにそれを行っています。ハックではありませんが、正しい解決策です。プロパティが使用される前に拡張が行われていることを確認してください:)

于 2016-10-07T08:09:21.320 に答える
1

あなたのオプションは、観察可能なマップextendObservableを使用しているか、使用しています。参照については、オブザーバブルのドキュメントを参照してください。具体的には次のとおりです。

動的にキーが設定されたオブジェクトを作成するには、asMap 修飾子を使用してください! オブジェクトの最初に存在するプロパティのみが監視可能になりますが、extendObservable を使用して新しいプロパティを追加できます。

于 2016-10-07T07:00:48.093 に答える