首页 文章

如何处理Flux商店中的一对多关系

提问于
浏览
13

我刚刚开始使用flux(现在使用redux),我想知道如何处理关系 .
举个例子,我们可以使用Trello,它有包含卡的列的板 .

一种方法是为板子安装一个存储/减速器,并在其中包含所有数据,但这意味着一些非常胖的存储,因为它们必须包含列和卡的所有操作 .

我见过的另一种方法是将嵌套资源分成例如BoardStore,ColumnStore和CardStore,并使用它们的id作为参考 .

这是一个我有点困惑的例子:你可以有一个名为addCard的动作创建者向服务器发出请求,创建一张包含所有数据的卡片 . 如果您正在进行乐观更新,您之前会在您的某个商店中创建一个卡片对象,但在您收到请求之前,您无法知道它将具有的ID .

简而言之:

  • 点击addCard

  • addCard发出请求,同时返回ADD_CARD_TEMP类型的操作

  • 您收到请求并返回类型为ADD_CARD的操作,其中存储/缩减器更改了ID .

有没有推荐的方法来处理这个案子?嵌套的存储/缩减器对我来说看起来有点傻,但是否则你最终会得到非常复杂的存储,所以它看起来真的很妥协 .

1 回答

  • 8

    是的,在多个商店中使用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) ,它将是卡片对象上的简单 Map ,这将生成一组可用于呈现列内容的卡片 .


    关于乐观更新的机制,以及id的使用如何影响它:

    您可以使用在将处理XHR响应的同一闭包内 Build 的客户端ID,并在响应成功返回时清除客户端ID,或者在错误时回滚 . 闭包允许您保持客户端ID,直到响应返回 .

    许多人将创建一个WebAPIUtils模块,该模块将包含与保留客户端ID和请求/响应的闭包相关的所有方法 . 操作创建者(或商店)可以调用此WebAPIUtils模块来发起请求 .

    所以你有三个动作:

    • 发起请求

    • 处理成功

    • 处理响应

    响应发起请求的操作,您的商店会收到客户端ID并创建记录 .

    为了响应成功/错误,您的商店再次接收客户端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:
        // ...
    }
    

    请不要过于关注这个实现的名称和细节的详细信息(可能存在拼写错误或其他错误) . 这只是解释模式的示例代码 .

相关问题