反应查询中的过滤器在第一次尝试时无法正常工作
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
来记忆它(仅在 personData
或 femalesOnly
更改时计算它 - 但这可能是过早的优化。
我试图使用过滤器从数组中只获取女性,但在第一次尝试反应查询时 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
来记忆它(仅在 personData
或 femalesOnly
更改时计算它 - 但这可能是过早的优化。