【问题标题】:React/react hooks: child component is not re-rendering after the state is changed?React/react hooks:状态改变后子组件不重新渲染?
【发布时间】:2020-06-26 13:36:39
【问题描述】:

我正在尝试执行以下操作的 react/react 钩子中的代码。

从父组件中获取对象数组作为prop 使用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 无法重新渲染子组件?如果是后者,排序后如何强制重新渲染?

有什么建议吗?谢谢!

【问题讨论】:

    标签: javascript reactjs sorting react-hooks


    【解决方案1】:

    array::sort

    sort() 方法对数组的元素进行就地排序,并 返回排序后的数组。默认排序顺序是升序,建 将元素转换为字符串,然后比较它们 UTF-16 代码单元值序列。

    这对您来说意味着存储在数组中的元素的顺序可能会发生变化,但数组是按原地排序的,这意味着返回相同的数组引用(与返回 new 的其他数组函数不同数组)。

    React 协调通过检查 state 和 props 进行,并做出一个整体假设,即如果下一个 state/prop 引用没有改变,那么值没有改变,因此返回最后计算的渲染 DOM。这是更新反应状态的重要细节......每次更新都需要引用一个新对象。

    在您的情况下,您只是 保存 对状态中的 current 数组的引用,对其进行变异并重新保存它。由于引用是稳定的并且不会改变,因此 react 不会重新渲染。

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

    【讨论】:

      【解决方案2】:

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

      在这里在线试用:

      【讨论】:

        【解决方案3】:

        React 通过执行浅对象相等性检查来检查道具和状态的变化。如果你将 state 设置为你从 state 接收到的同一个对象,React 会假设你中止了你的更改并且不做任何事情,即使对象上的属性发生了变化。

        关键是sort() 方法对数组进行就地排序,并返回对同一数组的引用。所以 React 将它视为同一个数组对象,即使它的条目的 orser 是不同的。

        解决办法是新建一个数组:

        let k = [...newarray];
        

        k 被传递给setnewarray 时,React 发现它是一个完全不同的对象,并触发重新渲染。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-04-07
          • 2020-01-13
          • 1970-01-01
          • 2020-07-07
          • 1970-01-01
          • 2020-02-05
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多