Typescript & ReactJS 如何动态设置状态

Posted

技术标签:

【中文标题】Typescript & ReactJS 如何动态设置状态【英文标题】:Typescript & ReactJS How To Dynamically Set State 【发布时间】:2019-04-02 01:21:16 【问题描述】:

我将此接口定义为我的状态:

interface State 
  id: string;
  name: string;
  description: string;
  dimensionID: string;
  file: File | null;
  operator: string;
  isFormValid: boolean;
  filename: string;
;

我有一个简单的变更处理程序:

  update = (event: React.FormEvent<htmlInputElement>): void => 
    const  name, value  = event.currentTarget;
    this.setState( [name]: value );
  ;

但是,这个错误被抛出:

Error:(109, 19) TS2345: Argument of type ' [x: string]: string; ' is not assignable to parameter of type 'State | Pick<State, "id" | "name" | "description" | "dimensionID" | "file" | "operator" | "isFormValid" | "filename"> | ((prevState: Readonly<State>, props: Readonly<Props>) => State | Pick<...>)'.
  Type ' [x: string]: string; ' is not assignable to type '(prevState: Readonly<State>, props: Readonly<Props>) => State | Pick<State, "id" | "name" | "description" | "dimensionID" | "file" | "operator" | "isFormValid" | "filename">'.
    Type ' [x: string]: string; ' provides no match for the signature '(prevState: Readonly<State>, props: Readonly<Props>): State | Pick<State, "id" | "name" | "description" | "dimensionID" | "file" | "operator" | "isFormValid" | "filename">'.

我的问题是:如何像我的 on change 处理程序尝试那样动态设置状态? 此处理程序用于表单的不同部分,因此我不知道需要更新哪个状态键。

更新:解决方案 从这个post

  update = (event: React.FormEvent<HTMLInputElement>): void => 
    const  name, value  = event.currentTarget;
    this.setState(prevState => (
      ...prevState,
      [name]: value,
    ))
  ;

有效!

【问题讨论】:

在你调用更新的地方绑定名字。 this.update.bind(null, name )。这样在更新函数中,您将同时拥有名称和事件作为参数 看看这个:github.com/DefinitelyTyped/DefinitelyTyped/issues/… 【参考方案1】:

例如。

update = (name: string, event: React.FormEvent<HTMLInputElement>): void => 
    const  value  = event.currentTarget;
    this.setState( [name]: value );
  ;

<input onChange=this.update.bind(null, 'first_name') value=this.state.first_name />

【讨论】:

【参考方案2】:

常量name 扩展为字符串。您使用的是哪个版本的 TS?

您可以这样投射,但这不是一个好习惯:

this.setState(
  [name]: value
 as Pick<State, keyof State>);

与此问题相关的错误:

https://github.com/Microsoft/TypeScript/issues/15534 https://github.com/Microsoft/TypeScript/issues/13948 https://github.com/DefinitelyTyped/DefinitelyTyped/issues/26635

【讨论】:

感谢您的链接!我的解决方案来自第二个链接:github.com/Microsoft/TypeScript/issues/… 看来这与我遇到的问题相同。不过,看起来它并没有用最新版本解决。我正在使用 v3.0.1。【参考方案3】:

您可以使用in keyof 关键字从 IState 对象中解构键/值。

创建你的 React 状态:

interface IState  "email" : string; 

创建一个表单类型,将键解构为 K,值解构为 T[K]:

type FormState<T> =  [K in keyof T]: T[K] ;
// T represents your IState
// to get the key use: [K in keyof T]
// to reference the value use: T[K]

然后将 IState 作为泛型类型参数传递给 FormState 类型:

FormState<IState>

现在您可以更新状态,将其转换为上述 FormState:

this.setState( [formStateItem]: (e.target.value as any)  as FormState<IState>);

在处理程序中可能如下所示:

handleChange = <T, K extends keyof IState>(formStateItem: K) => 
    return (e: ChangeEvent<HTMLInputElement>) => 
        this.setState( [formStateItem]: (e.target.value as any)  as FormState<IState>);
    
;

最后你可以像这样在你的 JSX 中使用:

onChange=this.handleChange("email")

【讨论】:

【参考方案4】:

最喜欢的解决方案铸造。

this.setState([name]: value as [P in keyof State]: State[P])
// or
this.setState([name]: value as Pick<State, keyof State>)

setState 传播前一个状态

this.setState((prevState) => ( ...prevState, [name]: value ));

这不检查类型。对于任何被困在转换中的人来说,这只是一个快速的解决方法。

this.setState<never>([name]: value)

相关链接

React setState

Github Tim Roes comment

【讨论】:

以上是关于Typescript & ReactJS 如何动态设置状态的主要内容,如果未能解决你的问题,请参考以下文章

TypeError:fs.​​existsSync 不是函数(Electron/ReactJS/Typescript)

缺少元素的“关键”道具。 (ReactJS 和 TypeScript)

在 ReactJS + Typescript 中加载 CSS 模块并重新连接反应

ReactJS 和 Typescript :引用一个值,但在此处用作类型 (TS2749)

当 ReactJS 遇到 TypeScript

typesafe 使用 reactjs 和 typescript 选择 onChange 事件