繁体   English   中英

TypeScript & React - 一个用于多个输入字段的 onChange 处理程序

[英]TypeScript & React - one onChange Handler for multiple input fields

假设我有一个包含多个输入字段的表单。 在正常的 ES6/React 中,我会创建一个方法,所有输入字段都将指向它们的onChange处理程序。 像这样的东西:

handleChange(e) {
    e.preventDefault();
    this.setState({[e.target.name]: e.target.value});
}

这在您有很多表单元素并且不必创建特定方法来处理每个元素的情况下很有帮助。

这在 TypeScript 中可能吗? 即使它不是类型安全的?

正如评论中所回答的,您可以在 JavaScript 中执行的所有操作也是有效的 TypeScript。

但是,我猜您会从 TypeScript 编译器中收到错误消息(取决于您设置的编译器选项)。

假设您的组件如下所示:

interface ComponentProps { }
interface ComponentState {
  name: string
  address: string
}

class MyComponent extends React.Component<ComponentProps, ComponentState> {
  handleChange(e) {
    e.preventDefault()
    this.setState({ [e.target.name]: e.target.value })
  }
}

我收到此错误:

==外部:(30,19):错误TS2345:类型'{[x:数字]的参数:任何; }' 不能分配给 'ComponentState' 类型的参数。

== 外部:类型 '{ [x: number]: any; 中缺少属性 'name' }'。

当使用noImplicitAny编译器选项(我喜欢使用)时,这个额外的错误:

== 外部:(28,16):错误 TS7006:参数“e”隐式具有“任何”类型。

如果您确定您的代码是正确的,您可以通过显式转换handleChange的参数和setState的参数来handleChange这些错误

  handleChange(e: any) {
    e.preventDefault()
    this.setState({ [e.target.name]: e.target.value } as ComponentState)
  }

我是这样解决这个问题的:

handleChange = (field: string) => (event) => {
    this.setState({ [field]: event.target.value } as Pick<State, any>);
};

...

<Input onChange={this.handleChange('myField')} />

接受的答案对我不起作用。

import React, { useState } from 'react';

const Form = () => {
  const [inputValues, setInputValues] = useState<{ [x: string]: string }>()

  const handleFormSubmit = async (e: React.MouseEvent<HTMLElement>) => {
    e.preventDefault()
    const data = {
      name: inputValues?.name,
      email: inputValues?.email,
      phone: inputValues?.phone,
      income: inputValues?.name
    }

    const requestOptions = {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(data)
    };

    try {
      const response = await fetch('https://xyz/form-submit', requestOptions)
      const res = await response.json()
      console.log(res)
    } catch (error) {
      console.log(error)
    }
  }

  const handleInputChange = (e: React.FormEvent<HTMLInputElement>) => {
    const { name, value } = e.currentTarget
    setInputValues(prevState => ({ ...prevState, [name]: value }))
  }

  return (
    <div className="Form">
      <div className="form-wrapper">
        <h1>Demo Form for React</h1>
        <form className="form">
          <input 
            className="form-input"
            name="name" 
            value={inputValues?.name || ''} 
            onChange={handleInputChange} 
            placeholder="Your Name"
            type="text"
            data-testid="form-input-name"
          />
          <input 
            className="form-input"
            name="phone" 
            value={inputValues?.phone || ''} 
            onChange={handleInputChange} 
            placeholder="Your Phone" 
            type="tel"
            data-testid="form-input-phone"
          />
          <input 
            className="form-input" 
            name="email"
            value={inputValues?.email || ''} 
            onChange={handleInputChange} 
            placeholder="Your Email" 
            type="email"
            data-testid="form-input-email"
          />
          <input 
            className="form-input"
            name="income"
            value={inputValues?.income || ''} 
            onChange={handleInputChange} 
            placeholder="Your Annual Income" 
            type="number"
            data-testid="form-input-income"
          />
          <button 
            className='form-submit'
            data-testid="form-submit" 
            onClick={handleFormSubmit}
          >
            Submit
          </button>
        </form>
      </div>
    </div>
  );
}

export default Form;

一个示例Typescript表单。 它的特点:

  • 单个onChange处理程序
  • 一个状态对象,我们可以在其中添加尽可能多的键值对,而无需打字稿编译器对我们大喊大叫。
  • 使用 ES2020 可选链接。
  • 在 DOM 元素上有 data-testid 以防你想运行一些单元测试。
  • 应根据其类型为输入字段提供自动完成功能。
  • 使用 fetch api 对端点进行后期调用的表单提交函数示例。

此外,使用这种方法,您不必使用@ts-ignoreany或对您的tsconfig进行更改。

请随心所欲地使用它。

在界面中,您必须根据您的代码调整状态的值,即 [e.target.name] 和 e.target.value 类型字符串或任何类型的字符串。

interface formState {
  //it can be  (name: string address: string)
  [key: string]: string;
}

handleChange(e: any) {
    this.setState({
      [e.target.name]: e.target.value
    });
  }

例如

interface LoginFormState {
      //can be
      //email: string
      //password: string
      [key: string]: string;
    }
    interface Props {}

    class LoginForm extends React.Component<Props, LoginFormState> {
      constructor(props: Props) {
        super(props);
        this.state = {
          email: "",
          password: ""
        };
        this.handleChange = this.handleChange.bind(this);
      }
      handleChange(e: any) {
        this.setState({
          [e.target.name]: e.target.value
        });
        // console.log("email", this.state.email);
      }

希望这有帮助

我认为这种方法也很容易理解:

interface FormData {
    firstName?: string,
    lastName?: string,
}


const [form, setForm] = useState<FormData | null>(null);

和 JSX

<input onChange={(e) => setForm({...form, firstName: e.target.value})}  />
<input onChange={(e) => setForm({...form, lastName: e.target.value})}  />

暂无
暂无

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

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