React : useEffect 更新状态,但不重新渲染视图
React : useEffect updates the state, but does not re-render the view
我想对一组对象进行排序。
但是我在这里卡了一会儿:当 props filterActivated
改变时,state 更新了(在浏览器的 react dev 工具中验证),但是没有重新渲染
我不明白为什么视图没有重新呈现,即使 ideasArray
正在更新。
这是我的组件:
import React, { useState, useEffect } from 'react'
// Components
import Idea from './Idea'
const IdeasContainer = ({ filterActivated }) => {
const [ideasArray, setIdeasArray] = useState([]);
useEffect(() => {
const getIdeas = async () => {
try {
const response = await fetch("http://localhost:3004/api/ideas")
const data = await response.json()
setIdeasArray(data)
} catch (err) {
console.error('getIdeas error: ', err, err.stack)
}
}
getIdeas();
}, []);
useEffect(() => {
const sorted = (array) => {
let newArray = array.sort(function (a, b) {
if (filterActivated === 'scoreAsc') {
return a.score - b.score
}
else if (filterActivated === 'scoreDesc') {
return b.score - a.score
}
});
setIdeasArray(newArray);
}
sorted(ideasArray);
}, [filterActivated, ideasArray]);
return (
<div className="ideasContainer">
{
ideasArray.map((idea, index) => {
return <Idea key={index} dataIdea={idea} />
})
}
</div>
)
}
export default IdeasContainer;
首先,您的useEffect
有几个问题:
如果您在 useEffect
中设置该值,请不要将 ideasArray 引用为 useEffect
依赖项。这将导致无限循环,因为当您设置值时,将再次调用 `useEffect,它设置值,再次调用它,设置值......等等。如果您依赖于先前的值来设置新值,请将 setter 函数传递给 setIdeasArray 函数,例如:
useEffect(() => {
setIdeasArray(oldValue =>
[...oldValue].sort((a, b) => {
if (filterActivated === "scoreAsc") {
return a.score - b.score;
} else if (filterActivated === "scoreDesc") {
return b.score - a.score;
}
})
);
}, [filterActivated]);
请注意我是如何在排序前将 oldValue
展开到一个新数组中的。这是因为 Array.sort
并非可靠地不可变,因此在某些情况下它会改变原始数据,这在 React 中是我们不希望发生的。
如果状态改变,总会有一个re-render。 React 的渲染周期与 DOM 变化不同,但如果 props 或 state 发生变化,React 仍将 运行 组件渲染周期。
您遇到的问题是由于每个想法都使用 index
作为 key
。使用索引作为键是一个非常糟糕的主意。
keys 的全部意义在于允许 React 识别数组中的项目而不必 re-render 它们,所以通过使用索引,你实质上是说第一个项目(总是index 0
) 永远不会改变。是的,你的状态是 re-ordered,但是 React 看到键没有改变顺序,所以它不会改变 DOM 来匹配。
键需要与项目相关(例如唯一 ID),以便 React 可以通过与“它在数组中的位置”无关的东西来识别该项目。
我想对一组对象进行排序。
但是我在这里卡了一会儿:当 props filterActivated
改变时,state 更新了(在浏览器的 react dev 工具中验证),但是没有重新渲染
我不明白为什么视图没有重新呈现,即使 ideasArray
正在更新。
这是我的组件:
import React, { useState, useEffect } from 'react'
// Components
import Idea from './Idea'
const IdeasContainer = ({ filterActivated }) => {
const [ideasArray, setIdeasArray] = useState([]);
useEffect(() => {
const getIdeas = async () => {
try {
const response = await fetch("http://localhost:3004/api/ideas")
const data = await response.json()
setIdeasArray(data)
} catch (err) {
console.error('getIdeas error: ', err, err.stack)
}
}
getIdeas();
}, []);
useEffect(() => {
const sorted = (array) => {
let newArray = array.sort(function (a, b) {
if (filterActivated === 'scoreAsc') {
return a.score - b.score
}
else if (filterActivated === 'scoreDesc') {
return b.score - a.score
}
});
setIdeasArray(newArray);
}
sorted(ideasArray);
}, [filterActivated, ideasArray]);
return (
<div className="ideasContainer">
{
ideasArray.map((idea, index) => {
return <Idea key={index} dataIdea={idea} />
})
}
</div>
)
}
export default IdeasContainer;
首先,您的useEffect
有几个问题:
如果您在 useEffect
中设置该值,请不要将 ideasArray 引用为 useEffect
依赖项。这将导致无限循环,因为当您设置值时,将再次调用 `useEffect,它设置值,再次调用它,设置值......等等。如果您依赖于先前的值来设置新值,请将 setter 函数传递给 setIdeasArray 函数,例如:
useEffect(() => {
setIdeasArray(oldValue =>
[...oldValue].sort((a, b) => {
if (filterActivated === "scoreAsc") {
return a.score - b.score;
} else if (filterActivated === "scoreDesc") {
return b.score - a.score;
}
})
);
}, [filterActivated]);
请注意我是如何在排序前将 oldValue
展开到一个新数组中的。这是因为 Array.sort
并非可靠地不可变,因此在某些情况下它会改变原始数据,这在 React 中是我们不希望发生的。
如果状态改变,总会有一个re-render。 React 的渲染周期与 DOM 变化不同,但如果 props 或 state 发生变化,React 仍将 运行 组件渲染周期。
您遇到的问题是由于每个想法都使用 index
作为 key
。使用索引作为键是一个非常糟糕的主意。
keys 的全部意义在于允许 React 识别数组中的项目而不必 re-render 它们,所以通过使用索引,你实质上是说第一个项目(总是index 0
) 永远不会改变。是的,你的状态是 re-ordered,但是 React 看到键没有改变顺序,所以它不会改变 DOM 来匹配。
键需要与项目相关(例如唯一 ID),以便 React 可以通过与“它在数组中的位置”无关的东西来识别该项目。