我正在使用 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
中所做的更改,因此不会重新渲染。
我对这个问题有一些疑问。
Person
中所做的更改)如果新状态中的每个元素与旧状态中的每个元素都是
===
,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
对象替换数组的第一个元素。
我发现如果你更新任何变量,它就会更新屏幕。我还没有彻底测试过这个。但我的假设是,解决这个问题的简单方法(虽然很hacky)是有一个简单的计数变量,您只需在每次想要更新屏幕时递增该变量即可
[counter, setCounter = useState(0);
let updateCounter = (){
setCounter(counter++);
}
然后当你想更新屏幕时,只需调用
updateCounter()
如果我确定这个黑客是否有效,我可能会稍后再回来查看