如何处理 Flux 商店中的一对多关系
How to handle one-to-many relationships in Flux stores
我刚刚开始使用 flux(目前使用 redux)并且想知道应该如何处理关系。
举个例子,我们可以使用 Trello,它有带有包含卡片的列的板。
一种方法是为板设置一个 store/reducer 并将所有数据都放在其中,但这意味着一些非常庞大的存储,因为它们还必须包含列和卡片的所有操作。
我见过的另一种方法是将嵌套资源分成例如 BoardStore、ColumnStore 和 CardStore,并使用它们的 ID 作为参考。
这里有一个我有点困惑的例子:你可以有一个名为 addCard 的动作创建者,它向服务器发出请求以创建一张包含所有数据的卡片。如果您正在进行乐观更新,您之前会在您的商店之一中创建一个卡片对象,但在您取回请求之前您无法知道它的 ID。
简而言之:
- 正在触发 addCard
- addCard 执行请求,同时您 return 类型为 ADD_CARD_TEMP
的操作
- 您收到请求和 return 类型为 ADD_CARD 的操作,其中 store/reducer 更改了 ID。
有没有推荐的处理这种情况的方法?嵌套 store/reducer 在我看来有点傻,但否则你最终会得到非常复杂的存储,所以它看起来真的是一种妥协。
是的,像关系数据库一样跨多个商店使用 ID 是正确的方法。
在你的例子中,假设你想乐观地将一张新卡片放在特定的列中,并且一张卡片只能在一列中(一列到多张卡片)。
您的 CardStore 中的卡片可能如下所示:
_cards: {
'CARD_1': {
id: 'CARD_1',
columnID: 'COLUMN_3',
title: 'Go to sleep',
text: 'Be healthy and go to sleep on time.',
},
'CARD_2': {
id: 'CARD_2',
columnID: 'COLUMN_3',
title: 'Eat green vegetables',
text: 'They taste better with onions.',
},
}
请注意,我可以通过 id 引用卡片,也可以在对象中检索 id。这使我可以使用 getCard(id)
之类的方法,还可以在视图层中检索特定卡片的 ID。因此我可以有一个方法 deleteCard(id)
被调用以响应一个动作,因为我知道视图中的 id。
在卡片商店中,您将拥有 getCardsByColumn(columnID)
,这将是卡片对象上的简单映射,这将生成一组卡片,您可以使用这些卡片来呈现列的内容。
关于乐观更新的机制,以及 ID 的使用如何影响它:
您可以使用在将处理 XHR 响应的同一闭包中建立的客户端 ID,并在响应成功返回时清除客户端 ID,或者在出现错误时回滚。闭包允许您保留客户端 ID,直到响应返回。
许多人会创建一个 WebAPIUtils 模块,其中包含与保留客户端 ID 和 request/response 的闭包相关的所有方法。操作创建者(或商店)可以调用此 WebAPIUtils 模块来发起请求。
所以你有三个动作:
- 发起请求
- 处理成功
- 处理响应
为响应发起请求的操作,您的商店会收到客户端 ID 并创建记录。
响应 success/error,您的商店再次收到客户端 ID,并将记录修改为具有真实 ID 的已确认记录,或者回滚记录。您还希望围绕该错误创建良好的用户体验,例如让您的用户重试。
示例代码:
// Within MyAppActions
cardAdded: function(columnID, title, text) {
var clientID = this.createUUID();
MyDispatcher.dispatch({
type: MyAppActions.types.CARD_ADDED,
id: clientID,
columnID: columnID,
title: title,
text: text,
});
WebAPIUtils.getRequestFunction(clientID, "http://example.com", {
columnID: columnID,
title: title,
text: text,
})();
},
// Within WebAPIUtils
getRequestFunction: function(clientID, uri, data) {
var xhrOptions = {
uri: uri,
data: data,
success: function(response) {
MyAppActions.requestSucceeded(clientID, response);
},
error: function(error) {
MyAppActions.requestErrored(clientID, error);
},
};
return function() {
post(xhrOptions);
};
},
// Within CardStore
switch (action.type) {
case MyAppActions.types.CARD_ADDED:
this._cards[action.id] = {
id: action.id,
title: action.title,
text: action.text,
columnID: action.columnID,
});
this._emitChange();
break;
case MyAppActions.types.REQUEST_SUCCEEDED:
var tempCard = this._cards[action.clientID];
this._cards[action.id] = {
id: action.id,
columnID: tempCard.columnID,
title: tempCard.title,
text: tempCard.text,
});
delete this._cards[action.clientID];
break;
case MyAppActions.types.REQUEST_ERRORED:
// ...
}
请不要太在意名字的细节和这个实现的细节(可能有错别字或其他错误)。这只是解释模式的示例代码。
我刚刚开始使用 flux(目前使用 redux)并且想知道应该如何处理关系。
举个例子,我们可以使用 Trello,它有带有包含卡片的列的板。
一种方法是为板设置一个 store/reducer 并将所有数据都放在其中,但这意味着一些非常庞大的存储,因为它们还必须包含列和卡片的所有操作。
我见过的另一种方法是将嵌套资源分成例如 BoardStore、ColumnStore 和 CardStore,并使用它们的 ID 作为参考。
这里有一个我有点困惑的例子:你可以有一个名为 addCard 的动作创建者,它向服务器发出请求以创建一张包含所有数据的卡片。如果您正在进行乐观更新,您之前会在您的商店之一中创建一个卡片对象,但在您取回请求之前您无法知道它的 ID。
简而言之:
- 正在触发 addCard
- addCard 执行请求,同时您 return 类型为 ADD_CARD_TEMP 的操作
- 您收到请求和 return 类型为 ADD_CARD 的操作,其中 store/reducer 更改了 ID。
有没有推荐的处理这种情况的方法?嵌套 store/reducer 在我看来有点傻,但否则你最终会得到非常复杂的存储,所以它看起来真的是一种妥协。
是的,像关系数据库一样跨多个商店使用 ID 是正确的方法。
在你的例子中,假设你想乐观地将一张新卡片放在特定的列中,并且一张卡片只能在一列中(一列到多张卡片)。
您的 CardStore 中的卡片可能如下所示:
_cards: {
'CARD_1': {
id: 'CARD_1',
columnID: 'COLUMN_3',
title: 'Go to sleep',
text: 'Be healthy and go to sleep on time.',
},
'CARD_2': {
id: 'CARD_2',
columnID: 'COLUMN_3',
title: 'Eat green vegetables',
text: 'They taste better with onions.',
},
}
请注意,我可以通过 id 引用卡片,也可以在对象中检索 id。这使我可以使用 getCard(id)
之类的方法,还可以在视图层中检索特定卡片的 ID。因此我可以有一个方法 deleteCard(id)
被调用以响应一个动作,因为我知道视图中的 id。
在卡片商店中,您将拥有 getCardsByColumn(columnID)
,这将是卡片对象上的简单映射,这将生成一组卡片,您可以使用这些卡片来呈现列的内容。
关于乐观更新的机制,以及 ID 的使用如何影响它:
您可以使用在将处理 XHR 响应的同一闭包中建立的客户端 ID,并在响应成功返回时清除客户端 ID,或者在出现错误时回滚。闭包允许您保留客户端 ID,直到响应返回。
许多人会创建一个 WebAPIUtils 模块,其中包含与保留客户端 ID 和 request/response 的闭包相关的所有方法。操作创建者(或商店)可以调用此 WebAPIUtils 模块来发起请求。
所以你有三个动作:
- 发起请求
- 处理成功
- 处理响应
为响应发起请求的操作,您的商店会收到客户端 ID 并创建记录。
响应 success/error,您的商店再次收到客户端 ID,并将记录修改为具有真实 ID 的已确认记录,或者回滚记录。您还希望围绕该错误创建良好的用户体验,例如让您的用户重试。
示例代码:
// Within MyAppActions
cardAdded: function(columnID, title, text) {
var clientID = this.createUUID();
MyDispatcher.dispatch({
type: MyAppActions.types.CARD_ADDED,
id: clientID,
columnID: columnID,
title: title,
text: text,
});
WebAPIUtils.getRequestFunction(clientID, "http://example.com", {
columnID: columnID,
title: title,
text: text,
})();
},
// Within WebAPIUtils
getRequestFunction: function(clientID, uri, data) {
var xhrOptions = {
uri: uri,
data: data,
success: function(response) {
MyAppActions.requestSucceeded(clientID, response);
},
error: function(error) {
MyAppActions.requestErrored(clientID, error);
},
};
return function() {
post(xhrOptions);
};
},
// Within CardStore
switch (action.type) {
case MyAppActions.types.CARD_ADDED:
this._cards[action.id] = {
id: action.id,
title: action.title,
text: action.text,
columnID: action.columnID,
});
this._emitChange();
break;
case MyAppActions.types.REQUEST_SUCCEEDED:
var tempCard = this._cards[action.clientID];
this._cards[action.id] = {
id: action.id,
columnID: tempCard.columnID,
title: tempCard.title,
text: tempCard.text,
});
delete this._cards[action.clientID];
break;
case MyAppActions.types.REQUEST_ERRORED:
// ...
}
请不要太在意名字的细节和这个实现的细节(可能有错别字或其他错误)。这只是解释模式的示例代码。