React和TypeScript中的表单具有DRY更改句柄

时间:2019-02-02 13:24:48

标签: reactjs forms typescript dry

我在寻找最好的方式来管理形式的状态与打字稿反应。我的简单表单具有两个值:loginpassword字段。我实施IState接口形式状态和DRY handleChange方法在状态存储新值,而不在每个render()执行再现功能。

interface IState {
  login: string;
  password: string;
}

class LoginForm extends React.Component<{}, IState> {
  public state = {
    login: "",
    password: "",
  };

  public render() {
    const { login, password } = this.state;
    return (
      <form>
        <input name="login" value={login} onChange={this.handleChange}/>
        <input name="password" value={password} onChange={this.handleChange} type="password"/>
      </form>
    );
  }

  private handleChange = (e: React.FormEvent<HTMLInputElement>) => {
    const { name, value } = e.currentTarget;
    const n = name as keyof IState;
    // @ts-ignore
    this.setState({
      [n]: value,
    });
  }
}

我使用本地HTML的name是用于存储字段名称属性。 n变量将仅具有loginpassword的值。任何其他值都是不可能的。我可以告诉打字稿的n变量是"login" | "password"文字类型?打字稿方面nstring式可变甚至使用:

const n = name as keyof IState;

const n = name as "login" | "password";

然后,当我除去// @ts-ignore,收到错误:

Type error: Argument of type '{ [x: string]: string; }' is not assignable to parameter of type 'IState | Pick<IState, "login" | "password"> | ((prevState: Readonly<IState>, props: Readonly<IProps>) => IState | Pick<IState, "login" | "password"> | null) | null'.
Type '{ [x: string]: string; }' is missing the following properties from type 'Pick<IState, "login" | "password">': login, password  TS2345

但当我进行硬编码时没有错误:

const n = "login";

有什么方法可以将"login" | "password"类型强制为n变量?或用于DRY handleChange,而不优化问题和纯打字稿的任何其它溶液?

2 个答案:

答案 0 :(得分:2)

我们可以使用Pick来确保您设置的是在IState界面中定义的密钥。

Pick - set state

private handleChange = (e: React.FormEvent<HTMLInputElement>) => {
    const { name, value } = e.currentTarget;
    this.setState({
        [name]: value
    } as Pick<IState, keyof IState>);
};

或者您可以使用Partial,这将使所有状态键为可选。

class App extends React.Component<{}, Partial<IState>> {
    // ... rest of component
}

答案 1 :(得分:0)

1.声明你的接口

interface IState {
  login: string;
  password: string;
}

2.声明你的状态

const [myState, setMyState] = useState<IState>()

3.声明你的onchange函数

const onChange=(e: any): void => {
    const { name, value } = e.currentTarget;
    setMyState({ ...myState, [name]: value });
}

4.声明你的标记

<input name="login" type="text" onChange={onChange}/>

我们使用spread函数来维护和更新状态注意,你需要用“name”属性命名标记元素,它应该与你的界面属性相对应

Spread syntax

React naming elements