为啥要使用 Object.assign() 来更新功能组件 props 的变化?

Posted

技术标签:

【中文标题】为啥要使用 Object.assign() 来更新功能组件 props 的变化?【英文标题】:Why to use Object.assign() to update functional component props change?为什么要使用 Object.assign() 来更新功能组件 props 的变化? 【发布时间】:2021-04-07 03:16:17 【问题描述】:

我有一个学生名单,我把他们展示在桌子上。有两个按钮指示我应该按哪个值对列表进行排序(姓名或出生日期)。当单击按钮并对列表进行排序时,列表本身正在排序,但如果我不使用 Object.assign(newList, oldList) 将列表分配给新列表,然后通过传递给更新状态函数 @ 来更新它,它不会更新987654327@。这是我的代码:

const students= [
  
    name: "John Done",
    year: 1,
    birthdate: "2020-01-24",
  ,
  
    name: "Another Done",
    year: 3,
    birthdate: "2002-02-20",
  ,
  
    name: "Jack London",
    year: 2,
    birthdate: "1800-01-04",
  ,
  
    name: "Text Name",
    year: 3,
    birthdate: "1990-02-24",
  ,
  
    name: "Name",
    year: 2,
    birthdate: "2005-04-01",
  ,
];

ReactDOM.render(<App students=students />, document.getElementById('root'));

function App( students ) 
  const [studentsList, setStudentsList] = useState(students);

  const sortByYear = () => 
    // let sortedstudents = [];
    // Object.assign(sortedStudents, studentsList);
    // sorteStudents.sort((a, b) => b.year - a.year);
    // console.log(sorteStudents);
    // setStudentsList(sortedStudents);
    studentsList.sort((a,b) => b.year - a.year));
    setStudentsList(studentsList);
  ;

const sortByDates = () => 
  // let sortedStudents = [];
  // Object.assign(sortedStudents, studentsList);
  // sortedStudents.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate));
  // console.log(sortedStudents);
  // setStudentsList(sortedStudents);
  studentsList.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate));
  setStudentsList(studentsList);
;

return (
<div className="App">
  <div>
    <label>
      Sort By
    </label>
    <button
      onClick=() => sortByYear()
    >
      Year
    </button>
    <button
      onClick=() => sortByDates()
    >
      Most Old
    </button>
  </div>
  <Students students=studentsList />
</div>
 );


学生组件

function Students( students ) 
return (
    <div>
      <table>
        <thead>
          <tr>
            <th>Name</th>
            <th>Year</th>
            <th>Date of birth</th>
          </tr>
        </thead>
        <tbody>
          students.map((student, index) => (
            <tr key=index>
              <td>student.name</td>
              <td>student.year.toString()</td>
              <td>student.birthdate</td>
            </tr>
          ))
        </tbody>
      </table>
    </div>
  );

因此,即使学生的列表正在排序,状态也不会更新,但是如果我将初始列表分配给新列表,然后对其进行排序,然后更新它正在工作的状态。

p>

作品

let sortedStudents = [];
Object.assign(sortedStudents, studentsList);
sortedStudents.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate));
//console.log(sortedStudents);
setStudentsList(sortedStudents)

不工作

studentsList.sort((a, b) => new Date(b.birthdate) - new Date(a.birthdate));
setStudentsList(studentsList);

所以问题是为什么我需要将我的studentsList 分配给新数组,特别是通过使用Object.assign() 以便setStudentsList() 会更新组件的状态?我刚开始学习 React,所以这些状态的实际工作方式让我很困惑。

我发现了类似的帖子

React Functional Component props does not update React functional components props value not updating Re render functional component on props change React: Passing down props to functional components

【问题讨论】:

React 根据前一个道具与下一个道具的相等性以及前一个状态与下一个状态的相等性来确定是否应该重新渲染。通过改变原始状态数组,之前的 studentList 与更新后的 studentList 具有引用相等性,并且 react 不会检测到它需要重新渲染。 sort 改变状态而assign 不会。 @BrianThompson 现在这完全有道理......您的评论回答了我的问题。请让我知道是否可以改进我的代码,因为我还不知道最佳实践。 你不想在这里Object.assign。你想要const sortedStudents = studentsList.slice();(或任何alternative that copies the array)。 @Miraziz lol 不会像“设计限制”那样称其为“最佳实践”。我相信 React 团队会喜欢让较短的版本“正常工作”,如果他们能够可靠且性能良好的话:P 【参考方案1】:

正如Brain 提到的: React 根据前一个道具与下一个道具的相等性以及前一个状态与下一个状态的相等性来确定是否应该重新渲染。通过改变原始状态数组,之前的 studentList 与更新的 studentList 具有引用相等性,并且 react 不会检测到它需要重新渲染。

因此,为了更改列表并让 React 检测到更改,需要使用(变异)数组的 ,而不是它的 reference

正如Bergi 暗示的那样:alternative that copies the array by value

【讨论】:

以上是关于为啥要使用 Object.assign() 来更新功能组件 props 的变化?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Object.assign 更新嵌套对象

vuejs 数据视图不更新

什么时候需要使用 Object.assign() 方法来复制一个对象的实例?

也来探讨一下Object.assign

Mongoose - 保存文档 Object.assign

Object.assign()合并对象