【问题标题】:TypeScript & React - one onChange Handler for multiple input fieldsTypeScript 和 React - 一个用于多个输入字段的 onChange 处理程序
【发布时间】:2017-01-25 23:06:38
【问题描述】:

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

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

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

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

【问题讨论】:

  • 为什么不可能?你有任何错误吗?究竟是什么问题?
  • 任何你可以在 JavaScript 中做的事情,你都可以在 TypeScript 中做。
  • @NitzanTomer @vutran:会导致错误TS2345

标签: javascript reactjs typescript


【解决方案1】:

正如 cmets 中所回答的,您可以在 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 })
  }
}

我收到此错误:

== External: (30,19): error TS2345: Argument of type '{ [x: number]: any; }' 不可分配给“ComponentState”类型的参数。

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

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

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

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

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

【讨论】:

    【解决方案2】:

    我这样解决了这个问题:

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

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

    【讨论】:

      【解决方案3】:
      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 对端点进行 post 调用。

      此外,通过这种方法,您不必使用@ts-ignoreany 或更改您的tsconfig

      请随心所欲地使用它。

      【讨论】:

      • 谢谢,在我看来,这是一个比最佳答案更好的答案!
      • 正是我所需要的。谢谢!
      【解决方案4】:

      在界面中,您必须根据您的代码塑造您的状态值,即 [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);
            }
      

      希望有帮助

      【讨论】:

        【解决方案5】:

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

        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})}  />
        

        【讨论】:

          猜你喜欢
          • 2022-11-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-05-31
          • 2021-08-09
          • 1970-01-01
          • 2014-01-28
          • 2020-12-09
          相关资源
          最近更新 更多