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

Posted

技术标签:

【中文标题】如何更改 Typescript 类实例中的值?【英文标题】:How do I change a value in an instance of a Typescript class? 【发布时间】:2022-01-20 16:41:41 【问题描述】:

我有一个水果课:

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

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

【问题讨论】:

【参考方案1】:

一些注意事项:

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

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

如您所见,React 的整个想法涉及不可变值(AKA 函数式编程)。考虑使用不可变的 setter (public changeName(name: string): Fruit) 编写类,您将能够编写像这样的漂亮声明性代码:&lt;button onClick=() =&gt; setFruit(fruit.changeName('banana'))&gt;

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

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

【讨论】:

我 99% 都在跟踪你,但我似乎无法编译它。我不确定您在哪里创建用于设置 useState 等的新类实例,或者即使您正在创建一个类实例以设置为 useState。无论如何,您可以为您的示例提供允许声明式 changeName 调用的代码? 不确定我是否遵循,但这不是一种 hacky 方法,即使不使用 React,您也不会触及现有对象,而是创建新对象。在不可变类上,“setter”只返回新实例。这就是函数式方法,它通常会产生更具声明性、更清晰的代码,因为您可以遵循工作流程,而不会在整个代码库中发生就地更新。在 google 中搜索“javascript 函数式编程不可变”。 > 您是否认为在类中也有相关方法的价值。是的,一个对象应该提供生命周期/更新方法;否则,使用它的代码会更加冗长,并且通常会破坏封装。 确实,这些是不同的东西。您必须创建新值以便 React 重新渲染,这就是重点。它的完成方式(使用虚拟 DOM 或其他)是一个实现细节。 没错:在 React 中,副作用只能在 useEffect 块内执行。您可以在类中添加一个有效的save 方法,或者您可以创建一个someFruitRepository.save(fruit) 来隔离持久性的模型/实体(这是一个实现细节)。在某些时候,您可以深入研究 hex/clean 架构。【参考方案2】:

所以,事情就是这样。这是行不通的。


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

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

然后,每次您的组件渲染时,您都会创建一个新的Fruit,其名称为1id,名称为"apple"。您在渲染后对该对象所做的任何更改都不会被看到,因为要看到组件需要重新渲染,这会从头开始创建一个新的Fruit


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

所以,假设你有这个:

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

但问题是状态应该是不可变的,这意味着如果状态要改变,它需要一个完全新的对象,并且禁止改变状态的一部分。 p>

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

所以要解决这个问题,您需要在更改状态时设置一个全新的对象。

这应该可行:

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>
    )


但那是烦人的孩子。这就是为什么不建议将可变实例置于状态中的原因。这意味着通常根本不需要类的实例,而且将对象存储在状态中通常要简单得多。

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

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

【讨论】:

以上是关于如何更改 Typescript 类实例中的值?的主要内容,如果未能解决你的问题,请参考以下文章

如何在angular 2 typescript项目中更改body类

React Typescript:在 React.FC 中设置状态以更改 React.Component 中的值

Typescript Angular - Observable:如何更改其值?

Material-UI Typescript 如何在组件类中从 makeStyle() 创建样式实例

从 Typescript 中的基类创建子类的新实例 [重复]

如何更改类中成员函数中的值?