代码之家  ›  专栏  ›  技术社区  ›  Benjamin M

React Redux商店布局:如何处理“添加项目”请求的“挂起”状态?

  •  1
  • Benjamin M  · 技术社区  · 6 年前

    示例存储:

    {
      todos: {
        byId: {
          "1": { id: "1", title: "foo" },
          "2": { id: "2", title: "bar" }
        },
        allIds: ["2", "1"]   // ordered by `title` property
      }
    }
    

    现在用户想要添加一个新的Todo条目:

    dispatch({
      type: 'ADD_TODO_REQUEST',
      payload: { title: "baz" }
    })
    

    这会触发一些API请求: POST /todos . 请求的状态是 pending 只要有 回应( success error ). 这也意味着,我没有 id 但对于新创建的Todo条目。

    现在我已经想将它添加到商店(并显示它)。但我当然不能把它加到 byId allIds ,因为它没有 身份证件 但是。

    问题1: 我应该如何改变我的商店布局,使这成为可能?

    响应到达后,有两种可能:

    1. 成功 :更新存储并设置 身份证件 新Todo项的属性。使用 dispatch({type:'ADD_TODO_SUCCESS', payload: response.id}) .

    2. 错误 :从存储中删除新的Todo项。使用 dispatch({type:'ADD_TODO_ERROR', payload: ???})

    现在这两个动作的减缩器必须在存储中找到相应的元素。但它没有标识符。

    问题2: 如果商店里没有,我怎么找 身份证件 ?


    其他信息:

    • 我在用react和redux saga
    • 应该可以有多个并发 ADD_TODO_REQUEST 同时跑步。尽管必须有可能有多个 悬而未决的 存储区中的Todo项。(例如,如果网络连接很慢,用户只需输入“title1”并点击“add”按钮,然后单击“title2”和“add”、“title3”和“add”。) 可以禁用 AddTodo 请求挂起时的组件。

    如何在应用程序中解决此类问题?

    编辑:还有更多:

    对于“更新”和“删除”Todo条目,应提供相同的功能:

    • 当用户编辑一个Todo条目,然后点击“保存”按钮时,该项应该在 悬而未决的 也要陈述,直到得到回应。如果是错误,则必须将旧版本的数据放回存储区(不需要从服务器请求)。

    • 当用户单击“删除”时,项目将立即消失。 但是 如果服务器响应是错误的,则应将该项放回列表中。

    如果有错误响应,这两个操作都应该恢复以前的数据。

    1 回复  |  直到 6 年前
        1
  •  0
  •   Benjamin M    6 年前

    我找到了一个简单的解决办法。 但我相信还有其他的可能性和更好的解决方案。

    将Todo项保留在两个单独的集合中:

    {
      todos: {
        byId: {
          "1": { id: "1", title: "foo" },
          "2": { id: "2", title: "bar" }
        },
        allIds: ["2", "1"],
        pendingItems: [
          { title: "baz" },
          { title: "42" }
        ]
      }
    }
    

    现在我可以在商店里“参照”找到它们。

    // handle 'ADD_TODO_REQUEST':
    const newTodoEntry = { title: action.payload.title };
    yield put({ type: 'ADD_TODO_PENDING', payload: newTodoEntry });
    try {
      const response = yield api.addTodoEntry(newTodoEntry);
      yield put({ type: 'ADD_TODO_SUCCESS', payload: { id: response.id, ref: newTodoEntry } });
    } catch(error) {
      yield put({ type: 'ADD_TODO_ERROR', payload: newTodoEntry });
    }
    

    减速器将如下所示:

    case 'ADD_TODO_PENDING':
      return {
        ..state,
        pendingItems: // add action.payload to this array
      }
    
    case 'ADD_TODO_SUCCESS':
      const newTodoEntry = { ...action.payload.ref, id: action.payload.id };
      return {
        ..state,
        byId: // add newTodoEntry
        allByIds: // add newTodoEntry.id
        pendingItems: // remove action.payload.ref from this array
      }
    
    case 'ADD_TODO_ERROR':
      return {
        ..state,
        pendingItems: // remove action.payload.ref from this array
      }
    

    有两个问题:

    1. 减速器 必须 使用对象引用。不允许reducer从的操作负载创建自己的对象 ADD_TODO_PENDING .

    2. 由于存在两个不同的集合,因此无法在存储区内轻松对Todo项进行排序。

    有两个解决方法:

    1. 使用客户端生成 uuid 只存在于项目内的S pending 国家。这样,客户可以很容易地跟踪一切。

    • a)添加某种 insertAtIndex 属性设置为挂起项。然后,React组件代码可以合并这两个集合,并以自定义顺序显示混合数据。

    • b)保持物品分开。例如,服务器数据库中已持久化项列表上方和下方的挂起项列表。