TypeScript& React - 一个用于多个输入字段的onChange Handler

时间:2017-01-25 23:06:38

标签: javascript reactjs typescript

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

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

这有助于您拥有大量表单元素并且不必创建特定方法来处理每个表单元素。

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

4 个答案:

答案 0 :(得分:8)

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

但是,我猜你会从TypeScript编译器中获得错误(取决于你设置的编译器选项)。

假设您的组件看起来像这样:

noImplicitAny

我收到了这个错误:

  

==外部:(30,19):错误TS2345:类型'{[x:number]的参数:any; }'不能赋值给'ComponentState'类型的参数。

     

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

使用handleChange编译器选项(我喜欢使用)时,这个附加错误:

  

==外部:(28,16):错误TS7006:参数'e'隐式具有'any'类型。

如果您确定自己的代码是正确的,可以通过显式转换setState的参数和 handleChange(e: any) { e.preventDefault() this.setState({ [e.target.name]: e.target.value } as ComponentState) }

的参数来消除这些错误。
val filledForm = userForm.fill(User("Bob", 18))

答案 1 :(得分:4)

我这样解决了这个问题:

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

...

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

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

答案 2 :(得分:1)

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

请随心所欲地使用它。

答案 3 :(得分:0)

在界面中,您必须调整状态值,即[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);
      }

希望获得帮助