简体   繁体   English

无法分配给“状态”,因为它是常量或只读属性

[英]Cannot assign to 'state' because it is a constant or a read-only property

When I do a search on this issue, I can only find questions that modify this.state directly somewhere in a method body instead of using this.setState() .当我搜索这个问题时,我只能找到直接在方法体的某个地方修改this.state而不是使用this.setState() My problem is that I want to set a starting state in the constructor as follows:我的问题是我想在构造函数中设置一个起始状态,如下所示:

export default class Square extends React.Component<any, any> {
  constructor(props: any) {
    super(props);
    this.state = {
      active: false
    };
  }

  public render() {
    ...
  }
}

The app fails to start with the following compile error:应用程序无法启动,出现以下编译错误:

Cannot assign to 'state' because it is a constant or a read-only property

And this is because in definition of React.Component we have:这是因为在React.Component定义中我们有:

readonly state: null | Readonly<S>;

So I'm not sure how to go about this.所以我不知道该怎么做。 The official react tutorial in JS directly assigns to this.state and says that it is an acceptable pattern to do so in the constructor, but I can't figure out how to do this with TypeScript. JS 中的官方 react 教程直接赋值给this.state并说在构造函数中这样做是可以接受的模式,但我无法弄清楚如何用 TypeScript 来做到这一点。

Before rolling back (as suggested by @torvin's answer), please read through https://github.com/DefinitelyTyped/DefinitelyTyped/pull/26813#issuecomment-400795486 .在回滚之前(如@torvin 的回答所建议),请通读https://github.com/DefinitelyTyped/DefinitelyTyped/pull/26813#issuecomment-400795486

This was not meant to be a regression - the solution is to use state as a property .这并不意味着回归 - 解决方案是使用state作为属性 It is better than previous approach (setting state in a constructor) because:它比以前的方法(在构造函数中设置state )更好,因为:

  • you don't need constructor at all anymore你根本不需要构造函数了
  • you can't forget to initialize state (it is now a compile-time error)你不能忘记初始化状态(它现在是一个编译时错误)

For example:例如:

type Props {}

type State {
  active: boolean
}

export default class Square extends React.Component<Props, State> {
  public readonly state: State = {
    active: false
  }

  public render() {
    //...
  }
}

Another approach:另一种方法:

type Props {}

const InitialState = {
  active: false
}

type State = typeof InitialState

export default class Square extends React.Component<Props, State> {
  public readonly state = InitialState

  public render() {
    //...
  }
}

This appears to be a recent change in @types/react introduced in commit 542f3c0 which doesn't work very well, considering the fact that Typescript doesn't support assigning parent's readonly fields in derived constructors.考虑到 Typescript不支持在派生构造函数中分配父级的只读字段这一事实,这似乎是在提交542f3c0中引入的@types/react的最新更改,但效果不佳。

I suggest rolling back to a previous version of @types/react .我建议回滚到@types/react的先前版本。 Version 16.4.2 appears to be the last one before the unfortunate change has been made.版本16.4.2似乎是进行不幸更改之前的最后一个版本。

You can pin the version by removing the ^ in your package.json :您可以通过删除package.json^来固定版本:

"devDependencies": {
  ...
  "@types/react": "16.4.2",

Also check out the discussion about this change on DefinitelyTyped github pull request page另请查看关于此更改的讨论绝对类型 github 拉请求页面

Because state is a readonly property of the component, it can't be set field-by-field, but you can still do:因为state是组件的只读属性,所以不能逐个字段设置,但你仍然可以这样做:

constructor(props: MyProps) {
  super(props);
  this.state = {
    // include properties here
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM