我有以下代码
setInterval(() => {
fetch(`/clusters?type=${type}`)
.then((response) => response.json()
.then((responseBody) => {
if(clusters !== responseBody.members)
setClusters(responseBody.members);
}))
.catch();
}, 5000);
由于clusters
在检查if(clusters !== responseBody.members)
clusters
始终为空时是异步设置的,因此哪种方法正确?我正在尝试这样做,以减少渲染次数,因为该请求每5秒发生一次
答案 0 :(得分:1)
那是因为您所获得的状态已经过时。您可以做的是使用useRef
创建一个引用,然后在另一个useEffect
内用状态的当前值更新该引用。然后在获取数据后,使用ref将其与状态进行比较,如下所示:
function App() {
const [clusters, setClusters] = useState([]);
const clustersRef = useRef(clusters);
useEffect(() => {
clustersRef.current = clusters;
});
useEffect(() => {
setInterval(() => {
fetch(`/clusters?type=${type}`)
.then((response) => response.json()
.then((responseBody) => {
if(clustersRef.current !== responseBody.members)
setClusters(responseBody.members);
}))
.catch();
}, 5000);
}, []);
}
希望这会有所帮助:)
答案 1 :(得分:0)
您可以将一个函数传递给setClusters
,该函数将当前状态作为参数。然后,您可以进行比较,如果有新内容,则返回新项,如果没有任何更改,则返回旧值。 React非常聪明,知道如果将state设置为 exact 相同的值,则不应重新渲染。
但是您还有另一个问题。如果您的状态没有改变,React已经足够聪明,不会重新渲染。但是您的状态 正在改变。您的api调用正在创建新的数据对象,这些数据对象无法直接与您的旧数据对象进行比较。
因此,您需要找出一种更好的方法来检测是否发生了更改。 ===
或!==
不会告诉您两个数组具有相同的项目,它们会告诉您它们是否是相同的确切数组实例。
[1,2,3] === [1,2,3] //-> false
因此,您必须想出一种方法来判断您是否有两个包含相同内容的数组。一种方法是从旧数据和新数据创建一串id,然后进行比较。 (假设clusters
是一个对象数组,上面有一些uniq id
)。您创建一个可以与另一个值进行比较的单个值,以查看是否有任何更改。
setClusters(prevClusters => {
const prevIds = prevClusters.map(member => member.id).sort().join('-')
const newIds = responseBody.members.map(member => member.id).sort().join('-')
if (newIds === prevIds) {
return prevClusters // nothing has changed, return previous value
} else {
return responseBody.members // return new values.
}
})