使用来自 React 查询的日期来过滤导致过多重新渲染的现有状态

Using date from React query to filter existing state causing too many re-renders

我正在使用 React 查询调用 api 来检索计划日期列表,供用户用来更新日历中的选定日期列表。 但是我不确定如何使用反应查询来做到这一点。目前,裸露的 setDates 导致了太多的重新渲染,因为它不在我通常用于 api 调用的 useEffect() 挂钩内。现在我正在使用反应查询我不知道把它放在哪里?

const SomeDateComponent = ({  }) => {

  const [selectedDates, setSelectedDates] = React.useState<selectedDates>({});
  .....
  
  const { data: existingSchedules } = useExistingScheduleDates(
    startDate,
    endDate,
    userIds.map((agent) => agent.userId),
  );

  
  setDates((selectedDates) => ({ ...selectedDates, ...existingSchedules }))

  return (....)

自定义挂钩:

export function useExistingScheduleDates(
  startDate: Date,
  endDate: Date,
  userIds: number[],
): QueryObserverResult<ExistingScheduleDates> {
  return useQuery(
    ['existingSchedules', startDate, endDate],
    () => {
      return apiCall( {
        route: '/schedulesExist',
        query: {
          startDate: format(startDate, dateFormat),
          endDate: format(endDate, dateFormat),
          userId: userIds,
        },
      });
    },
    {
      refetchOnWindowFocus: false,
    },
  );
}

你绝对不能/不应该在 渲染期间调用 useState 的 setter 函数,因为这违反了 React 的核心原则,即渲染函数应该纯洁。你可以做的是:

  • 在useEffect中设置
const { data: existingSchedules } = useExistingScheduleDates(...)

useEffect(() => {
    setDates(...)
}, [existingSchedules])
  • useQuery
  • onSuccess回调中设置
const { data: existingSchedules } = useQuery(
  'key',
  queryFn,
  {
    onSuccess: data => setDates(...)
  }
)

这两种方法都应该有效,但问题仍然存在:您为什么需要这样做? react-query 本身的状态管理器,因此实际上没有必要将其额外存储在客户端状态中。使用 react-query 的最佳方式是保持客户端状态和服务器状态分离。我建议将用户选择 (selectedDates) 存储在 useState 中,让服务器数据完全由 react-query (existingSchedules) 处理,并在需要时将它们组合到渲染函数中至:

const { data: existingSchedules } = useExistingScheduleDates(...)
const [selectedDates, setSelectedDates] = React.useState<selectedDates>({})

const someComputedThing = computeSomeThing(existingSchedules, selectedDates)

抱歉命名错误,我不知道 existingSchedules 如何与 selectedDates 一起工作,但我希望你能理解 :)