Обработка ввода с помощью хуков React

Я обнаружил, что есть несколько способов обработки пользовательского ввода текста с помощью хуков. Какой более предпочтительный или правильный способ обработки ввода с помощью хуков? Что бы вы использовали?

1) Самый простой хук для обработки ввода, но у вас больше полей, больше повторяющегося кода, который вам нужно написать.

const [username, setUsername] = useState('');
const [password, setPassword] = useState('');

Мероприятия:

onChange = {event => setPassword(event.target.value)}
onChange = {event => setUsername(event.target.value)}

2) Аналогично приведенному выше примеру, но с динамическим именем ключа.

const [inputValues, setInputValues] = useState({
  username: '', password: ''
});

const handleOnChange = event => {
  const { name, value } = event.target;
  setInputValues({ ...inputValues, [name]: value });
};

мероприятие:

onChange = {handleOnChange}

3) Альтернатива useState, и, как сказано в документации ReactJS, useReducer обычно предпочтительнее useState.

const [inputValues, setInputValues] = useReducer(
  (state, newState) => ({ ...state, ...newState }),
  {username: '', password: ''}
);

const handleOnChange = event => {
  const { name, value } = event.target;
  setInputValues({ [name]: value });
};

мероприятие:

onChange = {handleOnChange}

4) useCallback вернет запомненную версию обратного вызова, которая изменится только в том случае, если изменилась одна из зависимостей.

const [inputValues, setInputValues] = useState({ 
  username: '', password: '' 
});

const handleOnChange = useCallback(event => {
  const { name, value } = event.target;
  setInputValues({ ...inputValues, [name]: value });
});

мероприятие:

onChange = {handleOnChange}
использоватьОбратный звонок не имеет особого смысла без второго аргумента (массива зависимостей)... ИМХО useReduce более гибкий и менее подверженный ошибкам, чем useState для объектов
Aprillion 19.04.2019 16:17
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
109
1
166 672
6
Перейти к ответу Данный вопрос помечен как решенный

Ответы 6

Вот как я это делаю (при условии, что ваши входные данные должны быть внутри формы):

У меня есть компонент BasicForm, который я использую.

Он сохраняет все входные данные в объект в одном вызове useState().

Он проходит через useContext() состояние inputs вместе с функцией onChange() и функцией setInputInitialState(), чтобы входы устанавливали свое начальное состояние при первом монтировании. Он также передает onFocus, onBlur и имеет функции для проверки полей, которые я не показываю здесь, чтобы упростить код.

Таким образом, я могу легко создать форму с любым количеством входных данных, например:

<BasicForm
      isSubmitting = {props.isSubmitting}
      submitAction = { (formState) =>
        props.doSignIn(formState) }
    >
      <TextInput
        type='email'
        label='Email'
        name='email'
        placeholder='Enter email...'
        required
      />
      <TextInput
        type='password'
        label='Password'
        name='password'
        placeholder='Enter password...'
        min = {6}
        max = {12}
        required
      />
      <SubmitButton
        label='Login'
      />
    </BasicForm>

BasicForm.js

import FormContext from './Parts/FormContext';

function BasicForm(props) {

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

  function onChange(event) {
    const newValue = event.target.value;
    const inputName = event.target.name;
    setInputs((prevState)=> {
      return({
        ...prevState,
        [inputName]: {
          ...prevState[inputName],
          value: newValue,
          dirty: true
        }
      });
    });
  }

  function setInputInitialState(
    inputName,
    label='This field ',
    type,
    initialValue = '',
    min = false,
    max = false,
    required = false) {

    const INITIAL_INPUT_STATE = {
      label: label,
      type: type,
      onFocus: false,
      touched: false,
      dirty: false,
      valid: false,
      invalid: false,
      invalidMsg: null,
      value: initialValue,
      min: min,
      max: max,
      required: required
    };

    setInputs((prevState) => {
      if (inputName in prevState) {
        return prevState;
      }
      return({
        ...prevState,
        [inputName]: INITIAL_INPUT_STATE
      });
    });

  }

return(
    <FormContext.Provider value = {{
      onChange: onChange,
      inputs: inputs,
      setInputInitialState: setInputInitialState,
    }}>
      <form onSubmit = {onSubmit} method='POST' noValidate>
        {props.children}
      </form>
    </FormContext.Provider>
  );
}

TextInput.js

Входные данные используют хук useEffect(), чтобы установить их начальное состояние при монтировании.

function TextInput(props) {

  const formContext = useContext(FormContext);

  useEffect(() => {
    console.info('TextInput useEffect...');
    formContext.setInputInitialState(
      props.name,
      props.label,
      props.type,
      props.initialValue,
      props.min,
      props.max,
      props.required
    );
  },[]);

  return(
      <input
        type = {props.type}
        id = {props.name}
        name = {props.name}
        placeholder = {props.placeholder}
        value = {([props.name] in formContext.inputs) ?
                  formContext.inputs[props.name].value
                : props.initialValue || ''}
        onChange = {formContext.onChange}
        onFocus = {formContext.onFocus}
        onBlur = {formContext.onBlur}
      >
      </input>
      </div>
      {([props.name] in formContext.inputs) ?
          formContext.inputs[props.name].invalidMsg && <div><span> {formContext.inputs[props.name].invalidMsg}</span></div>
        : null}
    </div>
  );

...
}
Ответ принят как подходящий

Как насчет того, чтобы написать повторно используемую функцию, которая возвращает входное значение... и саму <input>:

 function useInput({ type /*...*/ }) {
   const [value, setValue] = useState("");
   const input = <input value = {value} onChange = {e => setValue(e.target.value)} type = {type} />;
   return [value, input];
 }

Затем это можно использовать как:

 const [username, userInput] = useInput({ type: "text" });
 const [password, passwordInput] = useInput({ type: "text" });

 return <>
   {userInput} -> {username} <br />
   {passwordInput} -> {password}
 </>;

не могли бы вы пролить больше света на синтаксис после возврата. Это кажется довольно новым для меня.

Jonathan Akwetey Okine 26.02.2020 10:23

@JonathanAkweteyOkine, если вы говорите о втором возврате, это сокращенный синтаксис для фрагментов React. См. также здесь: reactjs.org/docs/fragments.html

Marco 27.02.2020 23:45

@Марко, спасибо. Но синтаксис, о котором я говорил, это {userInput} -> {username}

Jonathan Akwetey Okine 02.03.2020 14:26
http://reactjs.org/docs/…
Jonas Wilms 02.03.2020 16:46

Нужно ли использовать префикс use в функциях, не использующих хуки?

Niyas Nazar 23.04.2020 08:24

@NiyasNazar нет, не нужно. На самом деле это заблуждение.

Jonas Wilms 23.04.2020 09:06

@Marco Стрелка -> просто отображается как текст и не имеет особого синтаксиса.

EmpireJones 29.04.2020 18:23

@JonasWilms не будет ли это перепривязывать прослушиватель onChange при каждом вызове?

duhaime 18.11.2020 12:40

@duhaime да, будет. Этот фрагмент не «готов к копированию и вставке», он предназначен для демонстрации того, как можно использовать хуки в случае, приведенном на самом минимальном примере. Конечно, вы можете добавить useCallback, чтобы справиться с этим.

Jonas Wilms 19.11.2020 20:09

Пожалуйста, не делайте этого. HTML — это ценное общественное благо. Абстрагирование фундаментального веб-кирпичика в функцию, подобную этой, а затем затуманивание окон с помощью useState и деструктурирование ошеломят ваших менее изобретательных коллег и отрежут их от мира совершенства HTML. 100 голосов за этот ответ заставляют меня думать, что я не в той группе пингвинов.

bbsimonbb 22.11.2021 17:40

Да, вы можете обрабатывать хуки реакции с помощью useState()

import React, {useState} from 'react'

export default () => {
    const [fName, setfName] = useState('');
    const [lName, setlName] = useState('');
    const [phone, setPhone] = useState('');
    const [email, setEmail] = useState('');

const submitValue = () => {
    const frmdetails = {
        'First Name' : fName,
        'Last Name' : lName,
        'Phone' : phone,
        'Email' : email
    }
    console.info(frmdetails);
}

return(
    <>
    <hr/>
    <input type = "text" placeholder = "First Name" onChange = {e => setfName(e.target.value)} />
    <input type = "text" placeholder = "Last Name" onChange = {e => setlName(e.target.value)} />
    <input type = "text" placeholder = "Phone" onChange = {e => setPhone(e.target.value)} />
    <input type = "text" placeholder = "Email" onChange = {e => setEmail(e.target.value)} />
    <button onClick = {submitValue}>Submit</button>
    </>
    )
}

Вот как я использую прямо сейчас:

  const [inputValue, setInputValue] = React.useState("");

      const onChangeHandler = event => {
        setInputValue(event.target.value);
      };

      <input
        type = "text"
        name = "name"
        onChange = {onChangeHandler}
        value = {inputValue}
      />

Собирался прокомментировать это. Это самый простой способ, который я чувствую. Кроме того, вот как Дэн Абрамов продемонстрировал это, вводя хуки здесь: youtube.com/watch?v=dpw9EHDh2bM @ 25:25

I_am_learning_now 19.07.2020 02:02

Это очень простой и органичный способ понять. Спасибо.

marcode_ely 17.08.2020 07:49

Однако вы должны обернуть onChangeHandler с useCallback.

Andreas Linnert 10.10.2020 14:38

почему @АндреасЛиннерт?

ncesar 18.10.2020 03:07

@ncesar Хорошо, обновленная информация: кажется, это не так просто. В этом случае простой вызов useCallback() требует больше производительности, чем экономит. Это полезно только в сочетании с дочерними компонентами, заключенными в React.memo().

Andreas Linnert 05.11.2020 22:26
function App(){
    const [name, setName] = useState("");
    const [istrue, Setistrue] = useState(false);
    const [lastname,setLastname]=useState("");
    
    function handleclick(){
       Setistrue(true);
    }
    
    return(
        <div>
            {istrue ? <div> <h1>{name} {lastname}</h1> </div> : 
            <div>
                <input type = "text" placeholder = "firstname" name = "name" onChange = {e =>setName(e.target.value)}/>
                <input type = "text" placeholder = "lastname" name = "lastname" onChange = {e =>setLastname(e.target.value)}/>
               <button  type = "submit" onClick = {handleclick}>submit</button>
            </div>}
        </div>
    )
    
    }

}

Вы не увидите упоминания об этом в документах React, но вы можете рассмотреть библиотеку форм, например Формик.

Это именно то, что упоминается в React Docs: reactjs.org/docs/forms.html#full-fledged-solutions.

Laiacy 16.02.2022 16:39

Другие вопросы по теме