【问题标题】:React setState dynamically using string使用字符串动态响应 setState
【发布时间】:2020-04-20 19:41:57
【问题描述】:

如何在 React 组件中动态设置和存在状态字段?

我目前的尝试导致以下方法,但它在 TypeScript 中不起作用:

export interface MaskCompanyDetailState {
    fieldId: number;
}

export class MaskCompanyDetail extends React.Component<MaskCompanyDetailProps, MaskCompanyDetailState> {

    public constructor(props: any) {
        super(props);

        // Set field defaults.
        this.state = {
            fieldId: 0,
        };
    }

    public componentDidMount() {
        const myField: string = 'fieldId';
        const myVal: number = 123;
        this.setState({[myField]: myVal});
        this.setState({myField: myVal});
    }
}

来自 TSLint 的 this.setState({[myField]: myVal}); 的错误消息:

类型参数 '{ [x: string]: number; }' 不可分配给“MaskCompanyDetailState |”类型的参数((prevState: Readonly, props: Readonly) => MaskCompanyDetailState | Pick<...>) |选择<...>'。 输入 '{ [x: string]: number; }' 缺少“Pick”类型的以下属性:fieldId、fieldCompanyName、fieldStreetName、fieldStreetNumber 和 4 个以上。ts(2345)

来自 TSLint 的 this.setState({myField: myVal}); 的错误消息:

类型参数 '{ myField: number; }' 不可分配给“MaskCompanyDetailState |”类型的参数((prevState: Readonly, props: Readonly) => MaskCompanyDetailState | Pick<...>) |选择<...>'。 对象字面量只能指定已知属性,并且“myField”类型不存在于“MaskCompanyDetailState | ((prevState: Readonly, props: Readonly) => MaskCompanyDetailState | Pick<...>) |选择<...>'.ts(2345)

已经有帖子here了,但是我不知道如何应用建议的IState接口。

【问题讨论】:

  • 您想为对象添加属性吗?或者你想使用myField 变量的值来动态设置属性名?
  • 为什么myField 键周围有引号?有点违背了计算属性的要点,{['myField']: 123}{myField: 123} 相同,我认为这不是您想要做的,我猜myField 是一个变量,在这种情况下它应该是{[myField]: 123}
  • 我已通过指定初始问题并提供更多代码来更新帖子。
  • 切向相关:“TSLint”指的是现已弃用的单独工具。您可能指的是“TypeScript”。

标签: reactjs typescript state tslint


【解决方案1】:

MaskCompanyDetailState接口中添加如下字段——

[key: string]: any;

即,

interface MaskCompanyDetailState {
    ... // existing fields
    [key: string]: any;
}

这意味着您允许在您的状态中设置具有string 类型的键和any 类型的值的任何属性。 这就是您链接的post 所说的。这是一个 Index Signature 的例子,它是 Typescript 的一个特性。

不建议这样做,因为从长远来看,它会影响代码的可读性,并且团队中的其他人可能会滥用它。但除了重新考虑您的设计之外,我不知道有任何其他解决方案可以解决您的困境。

【讨论】:

  • 是否可以设置 readonly 以便可以读取/写入现有字段,但阻止在运行时创建新字段的可能性?
  • [key: string]: any; 部分是索引签名,而不是真正的属性。我已编辑我的答案以包含更多信息的链接。虽然您可以将其设置为 readonly,但当您在代码中执行 this.setState({[myField]: myVal}); 时,您实际上是在运行时在状态中创建新的字段/属性。没有办法解决这个问题。
  • readonly 意味着您只能在状态上创建(并在数组的情况下进行变异)属性。 AFAIK,没有办法阻止人们在运行时使用Index Signature 创建新字段。我的建议是在MaskCompanyDetailState 中声明所有可能的字段,但将它们标记为可选,而不是使用Index Signature
猜你喜欢
  • 1970-01-01
  • 2018-03-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多