我正在用react / react钩子编写代码,试图执行以下操作。
从父组件获取对象数组作为道具
使用useState
挂钩将其设置为状态。
根据预期的过滤器(时间和评分)对状态进行排序,然后重新呈现子组件。
我看到的是,以下代码在排序后会更新状态,但是即使状态已更新,依赖于状态的子组件也不会重新呈现。我以为子组件会在状态改变时自动重新渲染?
import React, {useState} from 'react';
import ProfilePostspreview from './ProfilePostspreview';
function ProfileNavigation(props){
const [newarray, setnewarray]=useState(props.parray); //'parray' object passed as props and saved as 'newarray' state
const otc = () => { //Function to sort the state by time and set a new state
let k=newarray;
setnewarray(k.sort((a, b) => (a.time > b.time) ? -1 : 1 ));
}
const orc = () => { //Function to sort the state by rating and then time and set a new state
let k=newarray;
setnewarray(k.sort((a, b) => (a.rating > b.rating) ? -1 : (a.rating === b.rating) ? ((a.time > b.time) ? -1 : 1) : 1 ));
}
return (
<div>
<div className="sm_options"> //Component to trigger the otc and orc functions
<div className="sm_button" id="order_t" onClick={otc}>Sort by time</div>
<div className="sm_button" id="order_r" onClick={orc}>Sort by rating</div>
</div>
<div className="posts_preview_columns_p"> //This is dependent on the 'newarray' state but is not re-rendering even after the state is sorted and updated?
{newarray.map(na=>
<ProfilePostspreview
postThumbnail={na.photolink}
rating={na.rating}
time={na.time}
target={na.target}
/>
)}
</div>
</div>
);
}
export default ProfileNavigation;
这可能是什么原因?代码是否有问题,或者排序状态被认为不够强大,以至于React无法重新渲染子组件?如果是后者,该怎么办才能在排序后强制重新渲染?
有什么建议吗?谢谢!
答案 0 :(得分:5)
sort()
方法对数组中的元素进行适当排序,然后 返回排序后的数组。默认排序顺序是升序,内置 在将元素转换为字符串后,然后比较它们 UTF-16代码单元值的序列。
这对您来说意味着存储在数组中的元素的顺序可能会更改,但是数组在适当的位置排序,这意味着将返回相同的数组引用(与其他返回 new 的数组函数不同)数组)。
通过对状态和属性进行检查来进行反应协调,并进行整体假设,即如果下一个状态/属性引用未更改,则值也不会更改,并因此返回上一次计算的渲染DOM。这是更新反应状态的重要细节...每次更新都需要引用一个新对象。
在您的情况下,您只是保存对状态中 current 数组的引用,对其进行突变并重新保存。由于参考是稳定的且不会更改,因此反应不会重新呈现。
const otc = () => {
let k = newarray; // <-- saved array reference!!
setnewarray(k.sort((a, b) => (a.time > b.time) ? -1 : 1 ));
}
正确的反应方式是将当前数组值复制到一个 new 数组中,这样它将有一个新的对象引用。
const otc = () => {
const newSortedArray = [...newArray].sort(
(a, b) => (a.time > b.time) ? -1 : 1
); // spread old array values into new array, then sort
setNewArray(newSortedArray);
}
答案 1 :(得分:1)
通过进行浅层对象相等性检查来反应检查道具和状态的变化。如果将状态设置为与从状态接收到的对象相同,则React会假定您中止了更改并且不执行任何操作,即使对象的属性已更改。
关键是sort()
方法对数组进行适当排序,并返回对同一数组的引用。因此,即使其条目的顺序不同,React也将其视为相同的数组对象。
解决方案是创建一个新数组:
let k = [...newarray];
将k
传递给setnewarray
时,React认为它是一个完全不同的对象,并触发了重新渲染。
答案 2 :(得分:1)
Sort()
工作到位,这意味着您将无法通过直接退货获得想要的东西。
顺便说一句,您可以按照以下更好的格式编写sort()
const otc = () => {
const result = [...newarray];
result.sort((a, b) => b.time - a.time);
setNewarray(result);
};
const orc = () => {
const result = [...newarray];
result.sort((a, b) =>
a.rating !== b.rating ? b.rating - a.rating : b.time - a.time
);
setNewarray(result);
};
在此处在线尝试: