在 redux 应用程序中,在哪里为实体生成唯一 ID?
Posted
技术标签:
【中文标题】在 redux 应用程序中,在哪里为实体生成唯一 ID?【英文标题】:Where to generate unique IDs for entities in a redux application? 【发布时间】:2020-11-07 18:56:01 【问题描述】:我想允许用户多次将同一个服务器项添加到页面(id:5)。为了在我们的应用程序中跟踪这些项目,我们需要为每个实例生成一个唯一的 ID。
我们的项目具有关系数据,因此出于性能原因,我们可能会在 redux 存储中标准化 API 响应。
type Item = id: string;
type Sku = id: string;
type AppStore =
items: [id: string]: Items ,
skus: [id: string]: Skus ,
itemSkus: [id: string]: string[] ,
使用此 API
export interface IAPIResponse<T>
data?: T;
errors?: string[];
type IAPIItem =
id: string;
skus: Array<
id: string;
>;
在典型的 redux-thunk action creator 中请求数据:
export const addItem = () => async (dispatch) =>
dispatch(startedAddItem());
try
const response = await get <IAPIResponse<IAPIItem>>('/get/item/5');
dispatch(succeededAddItem(response));
catch (error)
console.error('Error', error);
dispatch(failedAddItem(error));
;
并用他们的相关数据填充我们的减速器:
// items reducer
case ItemAction.addSucceeded:
const apiItem = getApiResource(action.payload);
const apiErrors = getApiErrors(action.payload);
if (apiErrors) // Handle errors in state
if (apiItem)
const item = buildItem(apiItem);
return
...state,
[item.id]: item,
break;
// skus reducer
case ItemAction.addSucceeded:
const apiItem = getApiResource(action.payload);
const apiErrors = getApiErrors(action.payload);
if (apiErrors) // Handle errors in state
if (apiItem)
const skus = buildSkus(apiItem.skus);
const indexedSkus = ...skus.map(s => ( [s.id]: s )) ;
return
...state,
...indexedSkus,
break;
// itemSkus reducer
case ItemAction.addSucceeded:
const apiItem = getApiResource(action.payload);
const apiErrors = getApiErrors(action.payload);
if (apiErrors) // Handle errors in state
if (apiItem)
const item = buildLineItem(apiItem);
const skus = buildSkus(apiItem.skus);
return
[item.id]: skus.map(s => s.id),
break;
在这种模式下,我们无法可靠地为 Item 和 Skus 生成相同的唯一 ID,因为响应在多个 reducer 中进行解析。 Redux 建议我们必须在它到达 reducer 之前生成唯一 ID。
问题:我怎样才能适应这种模式来解析reducer之前的响应,同时保持读取嵌套api数据和解析reducer中的响应体错误的灵活性?
【问题讨论】:
我对“具有多个实例的商店项目”评论感到困惑。您能否为您正在尝试做的事情以及为什么/如何做进一步的解释? @markerikson 抱歉,我已经更新了那部分 :) 假设您正在制造一辆汽车并想要添加四个轮胎。轮胎在服务器上具有相同的 ID。但是在我们的客户端应用程序中,我们需要为每个轮胎生成一个唯一的 id 来跟踪它。 那么从应用程序用户流中,您需要在这个序列中的哪个位置开始使用这些 ID? “多个实例”实际上是从服务器返回的,还是根据用户交互在客户端上随着时间的推移添加的(即“添加左前轮胎”)? @markerikson 他们从服务器回来,即。用户单击“添加轮胎”,然后出现一个对话框,他们从数据库中选择预先存在的轮胎。所以他们添加了四个相同的轮胎。在将轮胎添加到 redux 商店之前,我需要生成 ID 那么服务器是否真的返回了tires: [, , , ]
?如果是这样,为什么不让服务器生成这些唯一 ID?还是我误解了这里的用法? (另请注意,目前这可能更容易在 Reactiflux #redux
频道中讨论)。
【参考方案1】:
在对 Discord 进行进一步讨论后,OP 提供了以下关键信息:
这里真的只有一个数据流片段
当用户单击“添加轮胎”时,React 应用程序可以从数据库中请求轮胎 (/tire/add/5
) 他们可以多次请求同一个轮胎 然后他们可以修改该轮胎的每个实例以具有独特的属性 点击“保存”会将汽车及其轮胎发送至/car/save
我的回答:
/tire/add
API 端点每次发送响应时都可以生成一个 UUID。或者,在客户端:
const addTire = (sku, otherData) =>
const response = await post(`/tire/add/$sku`, otherData);
response.data.id = uuid();
dispatch(tireAdded(response.data));
或者,特别是如果您使用 RTK:
const tiresSlice = createSlice(
name: "tires",
initialState,
reducers:
tireAdded:
reducer(state, action)
// whatever here
,
prepare(tireData)
return
payload: ...tireData, id: uiud()
)
总体:
不要在减速器中随意做任何事情 这意味着在您调度之前生成任何随机的东西 在调度包含该数据的操作之前,您可以根据需要对 API 响应进行预处理、修改和修改【讨论】:
您建议生成随机 ID,以便它们作为有效负载的一部分传递,而不是在 reducer 中生成? 是的,因为在 reducer 中生成 any 随机值使其不可预测,并且随机数生成被认为是“副作用”:redux.js.org/style-guide/…。现在,如果您在 reducer 中生成随机数,代码会运行吗?当然。但这不是首选方法。 感谢您的解释。我想一个 UI 组件可能需要负责确保任何 id 的全局唯一性呢?似乎最好留给减速器。 绝对不是我的建议 :) 例如,如果您需要在每次发送“添加项目”操作时生成唯一 ID,您可以在操作创建器中执行此操作。由于 RTK 为您生成动作创建者,因此它提供了“准备回调”作为这样做的一种方式:redux.js.org/tutorials/essentials/… 啊哈!我现在看到了不同。谢谢你:)以上是关于在 redux 应用程序中,在哪里为实体生成唯一 ID?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 redux 中的 axios 库为发布到 API 服务器的数据自动生成唯一 ID