【问题标题】:React Hooks: handle multiple inputsReact Hooks:处理多个输入
【发布时间】:2020-09-02 17:33:42
【问题描述】:

react docs forms section 上有以下使用类组件的示例:

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2
    };

    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === 'checkbox' ? target.checked : target.value;
    const name = target.name;

    this.setState({
      [name]: value
    });
  }

  render() {
    return (
      <form>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange} />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange} />
        </label>
      </form>
    );
  }
}

考虑到 Hooks 只能在 React 函数组件或自定义 React Hook 函数中调用,有没有办法使用 hooks 来代替?

【问题讨论】:

  • 你会发现钩子本质上是在功能组件中使用实例属性/方法的一种方式(你没有实例 - 提示,react 为你保留一个)。所以首先把你的组件变成一个函数,它就是render方法,然后撒上useState
  • 所以我制作了一个自定义钩子:const useInputs =[inputs, setInputs] = useState(''); setInputs({[e.target.name]: e.target.value}) 所以如果我在输入的 onChange 中调用它(如类示例中所示)我不能因为我不能在那里调用钩子。
  • 将状态挂钩放在函数顶部,并在 onChange 处理程序中调用 setInput 方法。此外,您的状态应该是一个对象,其键是字段名称,其值是字段值,就像在您的类组件中一样。另一件事,当使用钩子时,你只能通过使用函数签名来“修补”状态(给它一个部分对象)来设置 useState 钩子的状态
  • 有一个简单的反应表单包use-flat-form 用于类似的用例。

标签: javascript reactjs react-hooks


【解决方案1】:

您可以通过不使用 useCallback 挂钩来稍微清理@adam 的最终解决方案,而只需将 useState 挂钩用作受控组件。

const MyComponent = () => {
   const [inputs, setInputs] = useState({});
   const handleChange = e => setInputs(prevState => ({ ...prevState, [e.target.name]: e.target.value }));

   return (
     <> 
      <input name="field1" value={inputs.field1 || ''} onChange={handleChange} />
      <input name="field2" value={inputs.field2 || ''} onChange={handleChange} />
     </>
   )
}

【讨论】:

  • 这是对上述问题的最佳答案,简单明了
【解决方案2】:

例子

const MyComponent = () => {
   const [inputs,setInputs] = useState({});

   return (
     <> 
      <input key="field1" name="field1" onChange={({target}) => setInputs(state => ({...state,field1:target.value}))} value={inputs.field1}/>
      <input key="field2" name="field2" onChange={({target}) => setInputs(state => ({...state,field2:target.value}))} value={inputs.field2}/>
     </>
   )

}

你可以像这样传入初始值:

const MyComponent = (initialValues = {}) => {
   const [inputs,setInputs] = useState(initialValues);
   ...
}

编辑:根据@hamidrezacomment,一个不错的简短onChange

const MyComponent = (initialValues = {}) => {
   const [inputs,setInputs] = useState(initialValues);
   const onChangeHandler = useCallback(
     ({target:{name,value}}) => setInputs(state => ({ ...state, [name]:value }), [])
   );

   return (
     <> 
      <input key="field1" name="field1" onChange={onChangeHandler} value={inputs.field1}/>
      <input key="field2" name="field2" onChange={onChangeHandler} value={inputs.field2}/>
     </>
   )


}

等等等等等等

【讨论】:

  • 这个答案非常好,但有一件事使它成为这个问题的最佳答案,并且提示是 onChange 方法的缩短答案写 onChangeForField 和他们的方法 onCHangeForField 写 const onChangeForField = ({ target }) =&gt; setInputs(prevInputs =&gt; ({ ...prevInputs, [target.name]: target.value 。我的提示只是从方法中删除 fieldName 并从目标而不是函数中获取名称
【解决方案3】:

也许,在最后一个示例中 onChangeForField('...') 将在每次渲染时触发,所以也许你必须写 onChange={()=>onChangeForField('...')} 或者如果你想要传递的事件 onChange={(e)=>onChangeForField('...', e)}

【讨论】:

    【解决方案4】:

    添加到亚当的答案和那些正在寻找打字稿解决方案的人,

    interface MyIType {
        field1: string;
        ...
    }
    
    //Partial from typescript to make properties optional
    interface MyFormType extends Partial<MyIType> {}
    
    const [inputs,setInputs] = useState<MyFormType>(initialValues);
        
    const onChangeForField = useCallback(({target}) => 
        setInputs(_state => {
                return {
                    ..._state,
                    [target.name]: target.value,
                };
            }),
        []
    );
    

    【讨论】:

      【解决方案5】:

      如果您像我一样,在多个页面上使用相同的输入 id/name/key 进行多个输入,请尝试 value={data.xxx || ''} 。 完整代码:

      const [data, setData] = useState<any>({});
      
      const handleValueChanges = e => { 
          setData({
            ...data,
            [e.target.name]: e.target.value,
          });
      };
      
      <InputText  (using prime react)
          id="firstName"
          name="firstName"
          value={data.firstName || ''}
          onChange={handleUpdate}
      />
      

      【讨论】:

        【解决方案6】:

        从 v6 开始可以使用.forEach(),请参考the migrate guide

        [{name: "firstName", value: "Safwat" }, {name: "lastName", value: "Fathi", }].forEach(({name, value}) => setValue(name, value));
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2023-03-26
          • 2021-12-07
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多