React状态下更新对象数据成员不会触发重新渲染

问题描述 投票:0回答:2

我正在使用 TypeScript 和 React 尝试在 React 组件中实现我的自定义类型。但是,如果状态中对象的数据成员已更新,则组件不会重新渲染。

这是我的代码:

class Person {
  name: string;
  surname: string;

  constructor(name: string, surname: string) {
    this.name = name;
    this.surname = surname;
  }
}

class App extends Component<AppProps, AppState> {
  constructor(props) {
    super(props);
    this.state = {
      persons: [new Person("Alpha", "A"), new Person("Bravo", "B")]
    };
  }

  render() {
    return (
      <div>
        <button
          onClick={() => {
            this.state.persons[0].name = "Zulu";
            this.state.persons[0].surname = "Z";
          }}
        >
          Change A to Z
        </button>

        <button
          onClick={() => {
            this.setState({
              persons: [...this.state.persons, new Person("Charlie", "C")]
            });
          }}
        >
          Add C
        </button>

        <button onClick={() => { this.forceUpdate(); }}> Force Update </button>

        {this.state.persons.map(person => (
          <p>
            {person.name} {person.surname}
          </p>
        ))}
      </div>
    );
  }
}

完整代码片段

如果我点击

Change A to Z
,什么都不会改变 - 除非点击
Add C
Force Update
。我假设 React 无法检测到
Person
中所做的更改,因此不会重新渲染。

我对这个问题有一些疑问。

  • 是否建议在 React 中使用这种方法(自定义数据类型作为状态)
    • 如果是的话 - 我该如何进行这项工作? (React 能够检测
      Person
      中所做的更改)
    • 如果没有 - 在 React 中使用自定义数据类型的推荐方法是什么?
javascript reactjs typescript
2个回答
1
投票

如果新状态中的每个元素与旧状态中的每个元素都是

===
,React 默认情况下不会重新渲染。您还必须调用
setState
才能触发重新渲染。您的
Change A to Z
在这两个方面都失败了 - 您需要创建一个新的
persons
数组而不改变当前状态,然后使用新数组调用
setState

此外,拥有一个

Person
实例看起来并没有完成任何事情,因为类上没有方法 - 而且它会使更改状态变得更加困难,所以我会完全删除
Person
。尝试一下

  constructor(props) {
    super(props);
    this.state = {
      persons: [{ name: 'Alpha', surname: 'A' }, { name: 'Bravo', surname: 'B' }]
    };
  }

那就改变吧

      onClick={() => {
        this.state.persons[0].name = "Zulu";
        this.state.persons[0].surname = "Z";
      }}

onClick={() => {
  this.setState({
    persons: [{ name: 'Zulu', surname: 'Z' }, ...this.state.persons.slice(1)]
  });
}}

那个

persons: [{ name: 'Zulu', surname: 'Z' }, ...this.state.persons.slice(1)]

有效地、不可变地用新的

Zulu
对象替换数组的第一个元素。


0
投票

我发现如果你更新任何变量,它就会更新屏幕。我还没有彻底测试过这个。但我的假设是,解决这个问题的简单方法(虽然很hacky)是有一个简单的计数变量,您只需在每次想要更新屏幕时递增该变量即可

[counter, setCounter = useState(0);
let updateCounter = (){
    setCounter(counter++);
}

然后当你想更新屏幕时,只需调用

updateCounter()

如果我确定这个黑客是否有效,我可能会稍后再回来查看

© www.soinside.com 2019 - 2024. All rights reserved.