首页 > 解决方案 > 我必须在 React 钩子中使用扩展运算符的原因是什么?

问题描述

预期行为

每次点击时渲染计数器增加一个

实际行为

渲染计数器不会增加,但内部会增加(如警报消息所示)。看看这个截图: http: //prntscr.com/ujtsu9(它不会一直发生..)

代码

import React, { Component, useState } from "react";
import "./App.css";

function App(props) {
  const [all, setAll] = useState([{ name: "PHP", votes: 1 }]);

  function changeAll() {
    const newAll = all;
    alert(newAll === all); //alert true

    newAll[0].votes++;
    setAll(newAll);

    alert(all[0].votes);
  }

  return (
    <>
      <div className="voteCount">{all[0].votes}</div>
      <div className="lanugageName">{all[0].name}</div>
      <button onClick={changeAll}>Click Here</button>
    </>
  );
}

export default App;

我试过的:

将行const newAll = all;-> 更改为 ->const newAll = [...all]; 然后它可以工作。但是,然后警报说“假”

问题

标签: javascriptreactjsecmascript-6

解决方案


为什么我需要使用扩展运算符?

不需要使用扩展语法*,但您确实需要将要变异的现有状态浅层复制到新的对象/数组/内存引用中。使用扩展语法是实现此目的的方法之一。使用数组时,通常会使用许多返回数组的数组函数,即映射、过滤器、切片。

如果我使用扩展运算符 [语法*]为什么是newAll === all假的?

当您const newAll = all还将对状态的引用保存到时allnewAll但是您const newAll = [...all]首先将状态传播到的数组引用中,然后将其保存到newAll

试试看

const all = [1,2,3];

const newAll1 = all;
const newAll2 = [...all];

console.log(newAll1 === all); // true
console.log(newAll2 === all); // false

*传播语法

我还想提醒你不要使用这样的模式

newAll[0].votes++;
setAll(newAll);

即使您浅拷贝all,newAll[0].votes++仍然会被视为状态突变。如果您需要更新处于反应状态的数组元素,那么您应该浅拷贝您打算更新的任何对象的属性。

setAll(all.map((el, index) => !index ? el : { ...el, votes: el.votes + 1 }))

更重要的是,如果任何状态更新依赖于现有状态(增加计数是默认示例,顺便说一句),您将希望使用功能更新。

setAll(all => all.map((el, index) => !index ? el : { ...el, votes: el.votes + 1 }))

推荐阅读