有没有一种方法可以使用一个事件处理程序更新多个useState(反应挂钩)或一个useState(反应挂钩)的多个属性?

时间:2019-04-30 14:54:25

标签: reactjs react-hooks

我正在处理包含2个字段的登录表单。电子邮件和密码。当我使用代表两个字段的2 useState时,然后当我使用handleChange更新状态时,两个状态都将更新。这不是故意的。

   const [email, setEmail] = useState()
   const [password, setPassword] = useState()

    const handleChange = e => {
        const {value} = e.target
        setEmail(value)
        setPassword(value)
    }

我不想使用多个事件处理程序来处理每个输入字段。我尝试过

    const [state , setState] = useState({
        email : "",
        password : ""
    })

    const handleChange = e => {
        const {name , value} = e.target
        setState({
            [name] : value
        })
    }

但是这一次更新一个属性。并且其他财产价值迷失了。因此,有什么办法可以像使用状态组件一样,用一个事件处理程序更新所有输入字段。

    this.state = {
      email : "",
      password : ""
    }

    const handleChange = e => {
        const {name , value} = e.target
        this.setState({
           [name] : value
        })
    }

9 个答案:

答案 0 :(得分:1)

您可以使用react提供的UseReducer。它非常简单,并且提供了非常干净的代码。

import React, {useReducer} from 'react';

const initialState = {
    email: '',
    password: ''
};

function reducer(state, action) {
    switch (action.type) {
        case 'email':
            return {
                ...state,
                email: action.payload
            };
        case 'password':
            return {
                ...state,
                password: action.payload
            };
        default:
            throw new Error();
    }
}

const Login = () => {
    const [state, dispatch] = useReducer(reducer, initialState);
    const handleChange = event => dispatch({ type: event.target.name, payload: event.target.value.trim() });
    return (
        <div className="container">
            <div className="form-group">
                <input 
                    type="email"
                    name="email"
                    value={state.email}
                    onChange={handleChange}
                    placeholder="Enter Email"
                />
            </div>
            <div className="form-group">
                <input 
                    type="password"
                    name="password"
                    value={state.password}
                    onChange={handleChange}
                    placeholder="Enter Password"
                />
            </div>
            <div className="form-group">
                <button className="btn btn-info">Login</button>
            </div>
        </div>
    )
}

export default Login;

答案 1 :(得分:1)

您可以使用prevState。

const [state, setState] = useState({ fruit: "", price: "" });

  const handleChange = e => {
    const { name, value } = e.target;
    setState(prevState => ({
      ...prevState,
      [name]: value
    }));
  };

<input
        value={state.fruit}
        type="text"
        onChange={handleChange}
        name="fruit"
      />
      <input
        value={state.price}
        type="text"
        onChange={handleChange}
        name="price"
      />

答案 2 :(得分:0)

您应将setState与回调函数一起使用:

setState(prev => ({ 
    ...prev,
    email: 'new mail',
}))

您将创建一个新的状态对象,该对象由先前的状态创建。而且您可以覆盖所需的任何内容。 如果您有一个复杂的状态对象,则需要更多的新对象。

答案 3 :(得分:0)

尝试

this.state = {       电子邮件:“”,       密码:“”     }

const handleChange = e => {
    const updated = {name , value} = e.target
    const next = {...this.state, ...updated}
    this.setState({next})
}

答案 4 :(得分:0)

您可以像这样创建自定义钩子:

import React, { useState } from 'react';

export default function App() {
    const username = useFormInput(''); // use it here
    const password = useFormInput(''); // & here...
    return (
        <div>
            <form>
                <input type='text' placeholder='username' {...username} />
                <input type='password' placeholder='password' {...password} />
                <input type='submit' />
            </form>
        </div>
    );
}

// custom hook
function useFormInput (initialValue) {
    const [value, setValue] = useState(initialValue);
    const handleChange = event => {
        setValue(event.target.value);
    };
    return { value, onChange: handleChange };
};

答案 5 :(得分:0)

感谢DoğancanArabacı。我试图模仿基于类的组件的state和setState,所以感觉不会改变。我的解决方案如下所示。

const [state , setState] = useState({
    email : "",
    password : ""
})

const handleChange = e => {
    const {name , value} = e.target
    setState( prevState => {
        ...prevState,
        [name] : value
    })
}

答案 6 :(得分:0)

// The useState Hook is used in React,
const {obj, setObj} = useState({ // Initially a value of `{}` object type
  foo: {},
  bar: {}
})

const handle = event => {
  setObj({   // here `{}` is a new value of type object
    ...obj,  // So, first use the ... operator to get the prevState
    bar: { qux: {} } // then, update
  })
}

答案 7 :(得分:0)

尝试一下:

  const [email, setEmail] = useState('')
  const [password, setPassword] = useState('')

    const handleChange = (name, e) => {
      switch (name) {
      case 'email':
        setEmail(e);
        break;
      case 'password':
        setPassword(e);
         break;
       default:
       break;
    }
  };

您的输入:

<input
    type="text"
    onChange={ e => handleChange('email',e)}
    name="email"
  />
<input
    type="text"
    onChange={ e => handleChange('password',e)}
    name="password"
  />

答案 8 :(得分:0)

创建所有输入的字典

您可以使用输入的state保存对象(用作字典)中每个输入的setStatename的引用。

以下示例也适用于checkbox输入:

import React, { useState } from "react";
const setStateOfInput = 1;

function Form() {
  const inputs = {}; // Dictionary used to save a reference [state, setState] for each input (e.g. inputs.todo)
  const [todoInput, setTodoInput] = inputs.todo = useState("");
  const [doneInput, setDoneInput] = inputs.done = useState(false);

  function handleInput(e) {
    let { name, value, type } = e.target;
    // If input is a checkbox
    if (type === "checkbox") value = e.target.checked;

    inputs[name][setStateOfInput](value);
  }

  return (
    <div>
      <form>
        <label>To Do</label>
        <input name="todo" value={todoInput} onChange={handleInput} />

        <label>Done</label>
        <input name="done" type="checkbox" checked={doneInput} onChange={handleInput}/>

        <button type="button">Add</button>
      </form>
    </div>
  );
}

export default Form;

Edit react-hooks-controlled-component-form

创建自定义钩子

此外,可以重构以上内容以创建一个自定义钩子,该钩子可用于其他组件中的表单/输入:

function useInputState(initialValue, name, inputsDict) {
  if (inputsDict[name]) throw new Error(`input "${name}" already exists.`);

  inputsDict[name] = useState(initialValue);
  return inputsDict[name]
}

|

const inputs = {}; // Dictionary used by `useInputState`
const [todoInput, setTodoInput] = useInputState("", "todo", inputs);

Edit react-hooks-controlled-component-form