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

时间:2018-08-03 13:44:44

标签: reactjs asynchronous redux react-redux redux-saga

示例商店:

#standardSQL
SELECT *
FROM 
`myProject.analytics_159820162.events_*`
WHERE
_TABLE_SUFFIX BETWEEN '20180725' AND '20180727' 
AND event_name in ("event_notification_received", "event_notification_dissmissed")
AND platform = "ANDROID"
AND
(SELECT COUNTIF((key = "machine_name")) 
              FROM UNNEST(event_params) 
) > 0  -- to see if specified event has such key
AND
(SELECT COUNTIF((key = "Last_notification")) 
              FROM UNNEST(user_properties) 
) > 0  -- to see if specified event has such key
ORDER BY event_timestamp ASC

现在,用户要添加新的待办事项:

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

这会触发一些API请求:dispatch({ type: 'ADD_TODO_REQUEST', payload: { title: "baz" } }) 。只要没有没有响应(POST /todospending),请求的状态为success。这也意味着,对于新创建的Todo条目,我还没有error

现在我已经想将其添加到商店(并显示)。但是我当然不能将其添加到idbyId中,因为它还没有allIds

问题1:我应该如何更改商店的布局以实现此目的?

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

  1. id:更新商店并设置新Todo Entry的success属性。使用id

  2. dispatch({type:'ADD_TODO_SUCCESS', payload: response.id}):从商店中删除新的Todo Entry。使用error

现在,这两个动作的减速器必须以某种方式在商店中找到对应的元素。但是它没有标识符。

问题2:如果没有dispatch({type:'ADD_TODO_ERROR', payload: ???}),如何在商店中找到该物品?


其他信息:

  • 我正在使用redux-saga
  • 应该可以同时运行多个并发id。虽然必须在商店中有多个ADD_TODO_REQUEST待办事项。 (例如,如果网络连接确实很慢,并且用户仅输入“ title1”并单击“ add”按钮,然后单击“ title2”和“ add”,“ title3”和“ add”。)尽管不是 可以在请求待处理期间禁用pending组件。

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

编辑:还有更多:

“更新”和“删除”待办事项应具有相同的功能:

  • 当用户编辑Todo条目然后单击“保存”按钮时,该项目也应该也处于AddTodo状态,直到响应到达。如果出错,则必须将旧版本的数据放回存储中(无需从服务器请求)。

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

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

1 个答案:

答案 0 :(得分:0)

我找到了一个简单的解决方案。 但是我确信还有其他可能性,甚至还有更好的解决方案。

将Todo条目保留在2个单独的集合中:

{
  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
  }

有2个问题:

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

  2. 由于有两个不同的集合,因此在商店内无法轻松地分类Todo条目。

有两种解决方法:

  1. 使用客户端生成的uuid,它们仅在项目处于pending状态内时存在。这样,客户可以轻松跟踪所有内容。

2。

  • a)在待处理项目中添加某种insertAtIndex属性。然后,React组件代码可以合并这两个集合,并以自定义顺序显示混合的数据。

  • b)仅将项目分开。例如,服务器数据库中已经存在的项目列表的顶部和下方是未决项目的列表。