Я работаю над формой входа в систему с 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
Rakib Uddin 30 Апр 2019 в 17:54

7 ответов

Лучший ответ

Вы должны использовать setState с функцией обратного вызова:

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

Вы создадите новый объект состояния, который был создан предыдущим состоянием. И вы можете переопределить все, что вам нужно. Вам понадобится больше новых объектов, если у вас будет сложный объект состояния.

11
Doğancan Arabacı 30 Апр 2019 в 14:58

Благодаря Doğancan Arabacı. Я попытался имитировать состояние и setState из компонента на основе классов, чтобы ощущение не изменилось. Мое решение выглядит так.

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

const handleChange = e => {
    const {name , value} = e.target
    setState( prevState => ({
        ...prevState,
        [name] : value
    }))
}
13
shashwat 14 Мар 2020 в 17:50

Вы можете создать собственный хук следующим образом:

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 };
};
3
SakoBu 30 Апр 2019 в 17:03
// 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
  })
}
1
山茶树和葡萄树 27 Июн 2019 в 08:53

Вы можете использовать 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
Mohd Amir 5 Янв 2020 в 13:04

Вы можете использовать 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"
      />
1
manishk 13 Фев 2020 в 10:03

Пытаться

This.state = {email: "", пароль: ""}

const handleChange = e => {
    const updated = {name , value} = e.target
    const next = {...this.state, ...updated}
    this.setState({next})
}
0
dorriz 30 Апр 2019 в 15:04