反应查询中的过滤器在第一次尝试时无法正常工作

Filter in react query not working properly on first attempt

我试图使用过滤器从数组中只获取女性,但在第一次尝试反应查询时 returns 整个数组,之后它工作正常。知道我必须添加或删除什么 属性 ,所以这种副作用消失了。 这是我的代码:

import React, { useState } from "react";
import { useQuery } from "react-query";
import getPersonsInfo from "../api/personCalls";

export default function Persons() {
  const [persons, setPersons] = useState([]);
  const { data: personData, status } = useQuery("personsData", getPersonsInfo, {
    onSuccess: (data) => {
      setPersons(data.data);
    },
    onError: (error) => {
      console.log(error);
    }
  });

  const getFemaleOnlyHandler = () => {
    const result = personData.data.filter(
      (person) => person.gender === "female"
    );
    setPersons(result);
  };

  return (
    <>
      <button onClick={getFemaleOnlyHandler}>Female only</button>
      {status === "loading" ? (
        <div>Loading ... </div>
      ) : (
        <div>
          {persons.map((person) => (
            <div>
              <p>{person.name}</p>
              <p>{person.lastName}</p>
              <p>{person.address}</p>
              <p>{person.gender}</p>
              <p>{person.country}</p>
              <p>{person.city}</p>
            </div>
          ))}
        </div>
      )}
    </>
  );
}

我在代码沙箱中添加了完整代码:https://codesandbox.io/s/relaxed-drake-4juxg

我并不完全熟悉 react-query 但是问题很可能是每次组件更新时它都在重新获取(异步!)。由于 setPersons() 触发更新(即设置状态),它将更新新的 persons 状态为过滤后的女性列表,然后再次触发对所有人的提取,返回并设置 persons 状态回到完整列表(即,看看当你点击女性过滤器按钮然后离开它时会发生什么)。

在 React 中有一种更惯用的方法可以实现这一点,即保持 “单一事实来源”(即所有人)并根据一些地方 ui 州。

例如,请参见下面的示例,其中 data 成为事实来源,而 persons 是该事实来源的计算值。这样做的好处是,如果您的原始 data 发生变化,您不必手动(阅读:命令式)将其更新为仅限女性。这就是人们经常谈论的 “单向数据流”“反应性”,老实说,这就是让 React 成为 React 的原因。

  const { data = { data: [] }, status } = useQuery(
    "personsData",
    getPersonsInfo,
    {
      onSuccess: (data) => {},
      onError: (error) => {
        console.log(error);
      }
    }
  );
  const [doFilterFemale, setFilterFemale] = useState(false);

  const persons = doFilterFemale
    ? data.data.filter((person) => person.gender === "female")
    : data.data;

https://codesandbox.io/s/vigorous-nobel-9n117?file=/src/Persons/persons.jsx

这是假设您始终只是从 json 文件加载。在实际的应用程序设置中,给定一个你控制的后端,我总是建议在服务器端实现过滤、排序和分页,否则你将被迫在客户端过度获取。

我认为您错误地将数据从 react-query 复制到本地状态。思路是react-query 状态管理器,所以react-query返回的数据真的是你所需要的。

你在codesandbox中遇到的可能只是refetchOnWindowFocus。所以你关注 window 并单击按钮,react-query 将进行后台更新并覆盖你的本地状态。这是我刚才说的“复制”的直接结果。

您要做的只是存储用户选择,然后即时计算其他所有内容,如下所示:

const [femalesOnly, setFemalesOnly] = React.useState(false)
const { data: personData, status } = useQuery("personsData", getPersonsInfo, {
    onError: (error) => {
        console.log(error);
    }
});

const getFemaleOnlyHandler = () => {
    setFemalesOnly(true)
};

const persons = femalesOnly ? personData.data.filter(person => person.gender === "female") : personData.data

然后您可以显示您在 persons 中拥有的任何内容,这些内容将始终是最新的,即使后台更新会产生更多的人。如果计算(过滤)很昂贵,您还可以使用 useMemo 来记忆它(仅在 personDatafemalesOnly 更改时计算它 - 但这可能是过早的优化。