我的 useEffect
正在运行,但一旦完成,它就不会更新我的组件的状态。它总是显示之前的渲染。我想我已经添加了所有适当的依赖关系,但它仍然给我陈旧的数据。这是我的钩子。
export default function useSort(items, sortKey, sortAscending) {
let [sorted, setSorted] = useState(items);
useEffect(() => {
let sortedItems = sortKey ? items.sort((a, b) => {
if (!a[sortKey] && b[sortKey]) return sortAscending ? -1 : 1;
if (a[sortKey] && !b[sortKey]) return sortAscending ? 1 : -1;
if (a[sortKey] > b[sortKey]) return sortAscending ? 1 : -1;
if (a[sortKey] < b[sortKey]) return sortAscending ? -1 : 1;
return 0;
}) : items;
setSorted(sortedItems);
}, [items, sortKey, sortAscending]);
return sorted;
}
这是我使用它的组件:
const SearchResults = ({ columns, searchResults, sortAscending, sortKey }) => {
const dispatch = useDispatch();
let sorted = useSort(searchResults, sortKey, sortAscending);
return sorted.map((searchResult, index) => {
return ( ... )
}
SearchResult
渲染,但是当我试图对结果进行排序时(取决于我点击的列头),结果是 useEffect
代码运行。经过整理后。SearchResult
从来没有被重新渲染以显示变化。
我是如何错误地使用钩子的?正确的用法是什么?
JavaScript中的数组是 reference
类型;以及 setState
会导致当前值和之前值不同的组件重新渲染;与基元类型不同的是,引用类型只有在其引用发生变化时才会被标记为改变(即浅层比较)。在这种情况下,当你在原地突变数组时,从浅层比较的角度来看,前一个值和后一个值是一样的,这就像调用了 setState(2)
当 state
已是 2
人们已经在评论中提到,如果你返回新的数组(新的引用),就会解决这个问题;顺便看看下面的片段,看看这里发生的问题的具体例子。
ReactDOM.render(<Test/>, document.getElementById("root"))
function Test(){
const [array, setArray] = React.useState([2,3,4,5]);
const renderCounter = React.useRef(0);
function mutateInPlace(e){
renderCounter.current++;
// some random in-place mutations
array[1] = 4;
array[2] = 11;
array.sort((a,b)=>a-b);
setArray(array);
}
function mutateOutOfPlace(e) {
renderCounter.current++;
// creating a new array
let arrayCopy = array.slice(0);
setArray(arrayCopy);
}
console.log("re-rendered");
return (
<div>
{renderCounter.current}
<br/>
<button onClick={mutateInPlace}>mutate in-place</button>
<button onClick={mutateOutOfPlace}>mutate out-of-place</button>
</div>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.4/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.4/umd/react-dom.production.min.js"></script>
<div id="root"></div>