在哪里为 redux 应用程序中的实体生成唯一 ID?

Where to generate unique IDs for entities in a redux application?

我想允许用户多次将同一个服务器项目添加到页面 (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 操作创建者中请求数据:

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 建议我们必须在它到达 reducers 之前生成唯一 ID。

问题: 我如何调整此模式以在 reducer 之前解析响应,同时保持读取嵌套 api 数据和解析响应主体错误的灵活性减速器?

在对 Discord 进行进一步讨论后,OP 提供了以下关键信息:

There's really only one data flow piece here

  • The React application can request a tire from database when user clicks "add tire" (/tire/add/5)
  • They can request the same tire multiple times
  • They can then modify each instance of that tire to have unique properties
  • Click "save" will send the car and its tires to /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()}
        }
      }
    }
  }
})

总体:

  • 不要在 reducers 中做任何随机的事情
  • 这意味着在您发送
  • 之前生成任何随机内容
  • 在调度包含该数据的操作之前,您可以根据需要预处理、修改和破坏 API 响应