9

TL;博士

有什么方法可以像使用有状态组件一样使用一个事件处理函数动态更新输入字段的值。

我正在处理一个包含 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
        })
    }
4

9 回答 9

21

感谢 Doğancan Arabacı。我试图从基于类的组件中模仿 state 和 setState,所以感觉不会改变。我的解决方案看起来像这样。

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

const handleChange = e => {
    const {name , value} = e.target
    setState( prevState => ({
        ...prevState,
        [name] : value
    }))
}
于 2019-05-01T03:34:50.410 回答
20

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

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

您将创建一个由先前状态创建的新状态对象。你可以覆盖任何你需要的东西。如果您有一个复杂的状态对象,您将需要更多的新对象。

于 2019-04-30T14:58:06.203 回答
9

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

import { useState } from 'react';

export const useForm = (initialValues) => {
  const [values, setValues] = useState(initialValues);

  return {
    values,
    handleChange: (e) => {
      setValues({
        ...values,
        [e.target.name]: e.target.value,
      });
    },
    reset: () => setValues(initialValues),
  };
};

然后以任何形式使用它(例如):

export default function SignInForm() {
    const { values, handleChange, reset } = useForm({ username: '', password: '' });

    const handleSubmit = e => {
        e.preventDefault();
        reset();
    };

    return (
        <form onSubmit={handleSubmit}>
            <input
                type='text'
                name='username'
                placeholder='Enter your username...'
                onChange={handleChange}
                value={values.username}
            />
            <input
                type='password'
                name='password'
                placeholder='Enter your password...'
                onChange={handleChange}
                value={values.password}
            />
            <button type='submit'>
                Sign In
            </button>
        </form>
    );
}
于 2019-04-30T17:03:09.583 回答
1
// 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
  })
}
于 2019-06-27T08:53:50.333 回答
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;
于 2020-01-05T13:04:32.673 回答
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"
      />
于 2020-02-13T10:03:10.623 回答
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;

编辑 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);

编辑 react-hooks-controlled-component-form

于 2020-06-14T13:27:59.203 回答
0

尝试

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

const handleChange = e => {
    const updated = {name , value} = e.target
    const next = {...this.state, ...updated}
    this.setState({next})
}
于 2019-04-30T15:04:38.390 回答
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"
  />
于 2020-05-20T20:44:47.323 回答