如何更改 Typescript class 实例中的值?

How do I change a value in an instance of a Typescript class?

我有一个水果class:

export class Fruit {
    constructor(public id: number, public name: string) {}

    public changeName(_name: string): void {
        console.log('changing name')
        this.name = _name
    }
}

我是这样实现的:

import React from 'react'
import { Fruit } from '../classes/fruit'

const HomePage = () => {
    let fruit = new Fruit(1, 'apple')

    return (
        <div>
            {fruit.name} <----- I am expecting this to update on the DOM when i click the button *********
            <button onClick={() => fruit.changeName('banana')}>
                change the name
            </button>
        </div>
    )
}

export default HomePage

但是当我点击按钮时,屏幕上的水果名称并没有改变。它保持为 'apple' 。有谁知道我做错了什么?我是 Typescript 的新手

一些注意事项:

  • React 功能组件不是那样工作的。如果你的数据随时间变化,你需要定义一些状态,用一个钩子:const [fruit, setFruit] = React.useState(initialFruit).

  • 这仍然行不通,因为您的 fruit 是一个可变对象,React 不会“看到”就地命令更新。不理想,但你可以通过使用对象包装器作为状态值来欺骗 React:{ value: someFruit }(这是有效的,因为在 JS 中 { value: 1 } !== { value: 1 }.

  • 如您所见,React 的整个思想涉及不可变值(也称为函数式编程)。考虑用不可变的设置器 (public changeName(name: string): Fruit) 编写 类,你将能够编写像这样的漂亮的声明代码:<button onClick={() => setFruit(fruit.changeName('banana'))}>.

export class Fruit {
    constructor(public id: number, public name: string) {}

    public changeName(name: string): Fruit {
        return new Fruit(this.id, name)
    }
}

事情是这样的。这行不通。


首先,在 React 功能组件的渲染函数中创建的任何变量仅在该渲染期间存在。所以当你这样做时:

let fruit = new Fruit(1, 'apple')

然后,每次您的组件呈现时,您都会创建一个新的 Fruit,其 id1,名称为 "apple"。您在渲染后对 object 所做的任何更改将永远不会被看到,因为要看到该组件需要 re-rerender,这会从头开始创建一个新的 Fruit


解决这个问题的方法是使用“state”,它保留组件渲染之间的值。

所以,假设你有这个:

const HomePage = () => {
    let [fruit, setFruit] = useState(new Fruit(1, 'apple'))
    //...
}

但问题是状态应该是 不可变的,这意味着如果状态要改变,它需要一个新的 object 完全,并且它被禁止换一块状态。

这是因为除非您完全替换状态,否则 React 无法判断状态是否真的发生了变化。

因此,要解决此问题,您需要在更改状态时设置全新的 object。

这应该有效:

const HomePage = () => {
    let [fruit, setFruit] = useState(new Fruit(1, 'apple'))

    return (
        <div>
            {fruit.name}
            <button onClick={() => setFruit(new Fruit(fruit.id, 'banana')}>
                change the name
            </button>
        </div>
    )
}

但这真是个烦人的孩子。这就是为什么不建议将可变实例放入状态的原因。这意味着通常根本不需要 class 的实例,而且将 object 存储在状态中通常要简单得多。

// declare state
let [fruit, setFruit] = useState({ id: 1, name: 'apple' })

// set state
setFruit({ ...fruit, name: 'banana' })