我只是开始使用flux(现在使用redux),并且想知道应该如何处理关系。 例如,我们可以使用Trello,其板卡的列包含卡。
一种方法是在板上有一个存储/还原器,并在其中存储所有数据,但这意味着要存储很多数据,因为它们还必须包含列和卡的所有操作。
我见过的另一种方法是将嵌套资源分为例如BoardStore,ColumnStore和CardStore,并使用其ID作为参考。
这是一个让我有些困惑的示例:您可能有一个名为addCard的动作创建者,该动作创建者向服务器发出请求以创建包含所有数据的卡。如果您要进行乐观更新,那么您之前可能已经在您的一家商店中创建了证件对象,但是直到您取回请求之前,您才知道其证件号。
简而言之:
有没有建议的方法来处理这种情况?嵌套的存储/减速器对我来说看起来有点愚蠢,但否则您最终会遇到非常复杂的存储,因此看起来确实是一种折衷。
是的,正确地在多个商店中使用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。
getCard(id)
deleteCard(id)
在卡存储中,您将拥有getCardsByColumn(columnID),这是卡对象上的简单映射,这将产生卡阵列,可用于呈现列的内容。
getCardsByColumn(columnID)
关于乐观更新的机制,以及ID的使用如何影响它:
您可以使用在将处理XHR响应的同一个闭包中建立的客户端ID,并在响应成功返回时清除客户端ID,或者在发生错误时回滚。闭包允许您保留客户端ID,直到响应返回。
很多人会创建一个WebAPIUtils模块,其中将包含与关闭相关的所有方法,并保留客户端ID和请求/响应。动作创建者(或商店)可以调用此WebAPIUtils模块来发起请求。
因此,您有以下三个动作:
作为对发起请求的操作的响应,您的商店会收到客户端ID并创建记录。
作为对成功/错误的响应,您的商店再次接收到客户端ID,然后将记录修改为具有真实ID的已确认记录,或者回滚该记录。您还希望围绕该错误创建一个良好的UX,例如让用户重试。
示例代码:
// 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: // ... }
请不要太在意名称的细节和此实现的细节(可能存在拼写错误或其他错误)。这只是解释模式的示例代码。