如何在没有构造函数的情况下使用Typescript在React中正确设置初始状态?

时间:2018-10-10 20:46:45

标签: reactjs typescript class constructor

在现代JS中,我们可以像这样直接为React组件设置初始状态:

class App extends React.Component {
  state = {value: 10}

  render() {
    return <div>{this.state.value}</div>
  }
}

当我尝试使用Typescript进行此操作时,TSLint说“必须将类属性'state'标记为'private','public'或'protected'”。如果我将其设置为“私有”,则短绒将在Class 'App' incorrectly extends base class 'Component<{}, { value: number; }, any>'. Property 'state' is private in type 'App' but not in type 'Component<{}, { value: number; }, any>'.上报告App。我知道我可以调整linter规则以跳过这种检查,但是总体上检查类属性的可见性是我想利用的。

测试完所有三个选项之后,仅选择“ public”将不会得到TSLint抛出错误。但是,由于这里的状态代表此特定组件的内部状态,因此将其设置为public似乎很奇怪。我做对了吗?

class App extends React.Component<{}, { value: number }> {
  public state = { value: 10 };

  public render() {
    return <div>{this.state.value}</div>;
  }
}

在网上找到的所有TS-React教程中,都使用了构造函数,就像旧的JS语法一样。

class App extends React.Component<{}, { value: number }> {
  constructor(props: any) {
    super(props);
    this.state = { value: 10 };
  }

  public render() {
    return <div>{this.state.value}</div>;
  }
}

在Typescript中设置类属性是否直接被认为是不好的做法/风格?

3 个答案:

答案 0 :(得分:10)

  

我做对了吗?

是的

  

在Typescript中设置类属性是否直接视为不良样式?

否。

更好的方法

考虑将状态声明为public readonly,并使用Readonly modifier

这将满足TSLint的要求,同时还为您提供了一些保护,以免被错误修改(即不使用this.setState)。 即使状态仍然暴露在外部,这通常从来都不是问题。

interface IState {
  value: number;
}

class App extends React.Component<{}, IState> {
  public readonly state: Readonly<IState> = {
    value: 10
  }

  public render() {
    return <div>{this.state.value}</div>
  }
}

TSLint规则

显式声明访问修饰符是一件好事,即使它隐式导致相同的访问也是如此。它有助于保持代码清晰,因此我不会禁用此TSLint规则。

答案 1 :(得分:0)

我想说,直接设置React组件的public class Undergraduate extends Student { private int satScore; private String classYear; // ArrayList that maintains a list of valid department names for faculty members private ArrayList<String> classYearList; /** The constructor sets initial value for the class year field. * Explicit call to superclass Employee sets initial values for * fields firstName, lastName and studentID and gradePointAvg. * Instantiates and adds classYear to the 'classYearList' ArrayList. * * @param firstName Undergraduate Student's first name from indirect superclass Student * @param lastName Undergraduate Student's last name from indirect superclass Student * @param gradePointAvg the GPA of the Undegraduate Student * @param classYear the year of the Undergraduate Student */ public Undergraduate(String firstName, String lastName, int studentID, double gradePointAvg, int satScore, String classYear) { super(firstName, lastName, studentID, gradePointAvg); classYearList = new ArrayList<String>(); classYearList.add("FRESHMAN"); classYearList.add("SOPHMORE"); classYearList.add("JUNIOR"); classYearList.add("SENIOR"); setClassYear(classYear); setSatScore(satScore); } /** * Sets the sat score of the Undergraduates. * This sat Score must be between 600 and 2400 , or zero (0) meaning sat score not set. * * @param satScore sat Score range of Undergraduates */ public void setSatScore(int satScore) { if ( (satScore >= 600 && satScore <= 2400) || satScore ==0) { this.satScore = satScore; } } /** * Sets the degree earned as either Feshman, Sophmore, Junior, Senior. * * @param class year of the Undergraduates */ public void setClassYear(String classYear) { if (classYear.indexOf(classYear) >=0) { this.classYear = classYear; } } /**Returns current value of the satScore field. * *@return satsores of students as data type int. */ public int getSatScore() { return satScore; } /**Returns current value of the classYear field. * * @return class year of of students as data type String. */ public String getClassYear() { return classYear; } /** Returns fields satScore and classYear fields * including labels. * * @return Formatted sat score and class year fields as type String */ public String toString() { return super.toString() + "\nSat Score: " + getSatScore() + "\nClass Year: " + getClassYear(); } } 属性是一种不好的做法,除非您将类型注释为与{{1}的状态类型参数相同的类型,除非 }。如果没有注释,TypeScript将从初始值设定项中确定state的类型,从超类(基于状态类型参数)覆盖该类型,并且如果初始值设定项的类型出现则不会给您错误成为type参数的子类型。稍后可能导致不健全或意外行为;有关示例,请参见this thread

答案 2 :(得分:0)

状态是不可变的。推荐的设置初始状态的方法是通过构造函数。

请注意,“状态”已经定义并继承,因此无需重新声明:

interface AppState {
    charge : number;
    spin   : number;
    color  : string;
}

interface AppProps {}

class App extends React.Component<AppProps, AppState> {

    constructor(props) {
        super(props);
        this.state={ charge: 0, spin: -0.5, color:'red' }; 
    }
}

顺便说一句,这正是在react documentations中定义的方式:

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = {date: new Date()};
  }
...