【问题标题】:React setState for multi level state object为多级状态对象反应 setState
【发布时间】:2019-06-13 01:45:06
【问题描述】:

我正在尝试更新包含多个级别的状态对象。请参阅此示例https://codesandbox.io/s/oq9kp9vy5y

问题是,渲染方法中的值不会更新......只有第一个。我可以强制更新还是有更好的方法?

谢谢 卡斯帕

【问题讨论】:

  • 你应该包含相关的代码 sn-ps 而不是仅仅一个链接,因为链接可能会中断。
  • 为什么要在componentDidMount() 中设置状态?为什么不让它成为你的初始状态?
  • 您正在更新一个值 (state.kitchen) 并呈现另一个值 (state.calcuatedUsage.kitchen)。
  • 我实际上发现代码框链接非常有用。这让我更容易帮助调试。
  • @ShaneCavaliere "如果可以创建一个您可以链接到的问题的实时示例(例如,在 sqlfiddle.comjsbin.com 上),那么就这样做 - 但也包括代码在你的问题本身。不是每个人都可以访问外部网站,链接可能会随着时间的推移而中断。 - stackoverflow.com/help/how-to-ask

标签: reactjs setstate react-component react-state react-state-management


【解决方案1】:

试试这样的

import React, { Component } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      caclulatedUsage: {
        bath: 0,
        kitchen: {
          stove: 0,
          fridge: 0,
          dishwasher: 0
        },
        livingroom: {
          tv: 0,
          tvBox: 0
        }
      }
    };
  }

  componentDidMount() {
    this.setState(
      {
        caclulatedUsage: Object.assign({}, this.state.access, {
          caclulatedUsage: {
            ...this.state.caclulatedUsage,
            bath: 12
          },
          kitchen: {
            ...this.state.caclulatedUsage.kitchen,
            stove: 14,
            fridge: 23,
            dishwasher: 34
          }
        })
      },
      () => {
        console.log(this.state);
      }
    );
  }

  render() {
    return (
      <div className="App">
        <h1>Hello CodeSandbox</h1>
        {this.state.caclulatedUsage.bath}
        <br />
        {this.state.caclulatedUsage.kitchen.stove}
        <br />
        {this.state.caclulatedUsage.kitchen.fridge}
        <br />
        {this.state.caclulatedUsage.kitchen.dishwasher}
      </div>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

【讨论】:

  • 这应该是正确的 永远不要改变 this.state 。将 this.state 视为不可变的。但是在 componentDidMount() 中设置状态有什么意义呢?
  • 这个例子在this.setState调用内部访问this.state,这不是一个好主意。如果更新时需要访问之前的状态,请使用this.setState的功能版。
【解决方案2】:

试试:

  componentDidMount() {
    this.setState(
      {
        caclulatedUsage: {
          ...this.state.caclulatedUsage,
          bath: 12,
           kitchen: {
               ...this.state.caclulatedUsage.kitchen,
               stove: 14,
               fridge: 23,
               dishwasher: 34
           }
        }

      }
      () => {
        console.log(this.state);
      }
    );
  }

【讨论】:

  • 这个例子在this.setState调用内部访问this.state,这不是一个好主意。如果更新时需要访问之前的状态,请使用this.setState的功能版。
【解决方案3】:

在初始状态下,kitchen 对象 calculatedUsage 对象中。但是在你的setState 调用中,你有calculatedUsagekitchen 对象outside

另外,当您在setState 中访问之前的状态时,最好使用setState 的功能版本,例如:

componentDidMount() {
  this.setState(
    prevState => ({
      caclulatedUsage: {
        ...prevState.caclulatedUsage,
        bath: 12,
        kitchen: {
          ...prevState.caclulatedUsage.kitchen,
          stove: 14,
          fridge: 23,
          dishwasher: 34
        }
      }
    }),
    () => {
      console.log(this.state);
    }
  );
}

这样做的原因是setState 可以是异步的,这意味着在其中访问this.state 可能不会给您期望的值。使用功能版本进行事务状态更改可确保结果一致。

您可能还想看看immer 库。通过允许您使用可变 API 进行不可变更新,它使更新深度嵌套的状态变得更加容易。这是使用 immer 的 codeandbox 示例的一个分支:https://codesandbox.io/s/180p7p0o84

【讨论】:

  • ...Immer 看起来很棒,我会试一试。
猜你喜欢
  • 1970-01-01
  • 2021-01-28
  • 2021-06-02
  • 1970-01-01
  • 2019-05-31
相关资源
最近更新 更多