【问题标题】:Where to generate unique IDs for entities in a redux application?在 redux 应用程序中,在哪里为实体生成唯一 ID?
【发布时间】: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 频道中讨论)。

标签: reactjs typescript redux api-design redux-thunk


【解决方案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/…
  • 啊哈!我现在看到了不同。谢谢你:)
猜你喜欢
  • 1970-01-01
  • 2023-03-15
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
  • 1970-01-01
  • 2015-05-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多