Jing Chen (Flux の作成者およびエバンジェリストの 1 人)が提案したアプローチは、ストアに到達する前に API 応答をフラットにすることでした。私はそれを行う小さなライブラリを書きました:それは正規化します
[{
id: 1,
title: 'Some Article',
author: {
id: 1,
name: 'Dan'
}
}, {
id: 2,
title: 'Other Article',
author: {
id: 1,
name: 'Dan'
}
}]
に
{
result: [1, 2],
entities: {
articles: {
1: {
id: 1,
title: 'Some Article',
author: 1
},
2: {
id: 2,
title: 'Other Article',
author: 1
}
},
users: {
1: {
id: 1,
name: 'Dan'
}
}
}
}
(重複がなく、構造がフラットであることに注意してください。)
Normalizrでは次のことができます。
- エンティティを他のエンティティ、オブジェクト、および配列内にネストする
- エンティティ スキーマを組み合わせて、あらゆる種類の API 応答を表現する
- 同じ ID を持つエンティティを自動的にマージ (異なる場合は警告あり)
- カスタム ID 属性 (スラッグなど) を使用する
これを使用するには、エンティティとネスト ルールを定義し、それらを使用して JSON を変換する必要があります。
var normalizr = require('normalizr'),
normalize = normalizr.normalize,
Schema = normalizr.Schema,
arrayOf = normalizr.arrayOf;
// First, define a schema:
var article = new Schema('articles'),
user = new Schema('users'),
collection = new Schema('collections');
// Define nesting rules:
article.define({
author: user,
collections: arrayOf(collection)
});
collection.define({
curator: user
});
// Usage:
// Normalize articles
var articlesJSON = getArticleArray(),
normalized = normalize(articlesJSON, arrayOf(article));
// Normalize users
var usersJSON = getUsersArray(),
normalized = normalize(usersJSON, arrayOf(user));
// Normalize single article
var articleJSON = getArticle(),
normalized = normalize(articleJSON, article);
これにより、XHR レスポンスを Flux Dispatcher に渡す前に正規化できます。ストアは、対応する辞書から自身を更新するだけで済みます。
// UserStore
UserStore.dispatchToken = AppDispatcher.register(function (payload) {
var action = payload.action;
switch (action.type) {
// you can add any normalized API here since that contains users:
case ActionTypes.RECEIVE_ARTICLES:
case ActionTypes.RECEIVE_USERS:
// Users will always be gathered in action.entities.users
mergeInto(_users, action.entities.users);
UserStore.emitChange();
break;
}
});
// ArticleStore
AppDispatcher.register(function (payload) {
var action = payload.action;
switch (action.type) {
// you can add any normalized API here since that contains articles:
case ActionTypes.RECEIVE_ARTICLES:
// Wait for UserStore to digest users
AppDispatcher.waitFor([UserStore.dispatchToken]);
// Articles will always be gathered in action.entities.articles
mergeInto(_articles, action.entities.articles);
ArticleStore.emitChange();
break;
}
});