React / react钩子:状态更改后子组件是否未重新渲染?

时间:2020-03-15 02:03:58

标签: javascript reactjs sorting react-hooks

我正在用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无法重新渲染子组件?如果是后者,该怎么办才能在排序后强制重新渲染?

有什么建议吗?谢谢!

3 个答案:

答案 0 :(得分:5)

array::sort

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);
};

在此处在线尝试:

Java by Comparison