Привет, мир!

Когда мы работаем с формами в React, мы можем столкнуться с проблемой, из-за которой мы не сможем вводить текст в поле ввода/текстовое поле, если установлено свойство value. Я бы показал, в чем проблема и как я ее исправил.

Сценарий

Требование

У меня есть API, для которого потребуются три поля, а именно электронная почта, имя и сообщение, которые необходимо передать в теле API. В пользовательском интерфейсе мы будем получать эти значения в поле ввода или текстовой области и будем использовать кнопку для запуска вызова API.

Структура, ожидаемая в API, выглядит примерно так:

{
"email": "[email protected]",
"name": "Test",
"message": "Hi, this is a test message."
}

Выполнение

В приложении React я создал компонент с двумя полями ввода для получения name и email, текстовой областью для получения message и кнопкой для запуска вызова API и отправки трех значений. Вот как выглядел компонент:

import { useState } from "react";
import callApi from "../axios/axios";
import "./contact.scss";
const Contact = () => {
  const payloadInitial = {
    sender: "",
    email: "",
    message: "",
  };
  const initialClass = "form-input";
  const [payload, setPayload] = useState(payloadInitial);
  // Captures Sender name
  const setName = (name) => {
    const temp = payload
    temp.sender = name
    setPayload(temp)
  };
  // Captures Email
  const setEmail = (email) => {
    const temp = payload
    temp.email = email
    setPayload(temp)
  };
  // Captures Message
  const setMessage = (message) => {
    const temp = payload
    temp.message = message
    setPayload(temp)
    checkCanSend();
  };
  // Triggers API call on button click
  const sendMessage = (evt) => {
    evt.preventDefault();
    callApi
      .post("/email", payload)
      .then((res) => {
        console.log("Response: ", res)
      })
      .catch((err) => {
        console.error("Something went wrong: ", err)
      });
  };
  return (
    <div className="form-container">
      <h2 className="form-title">Write to me</h2>
      <div className="form-container">
        <!--Input to get sender name-->
        <label>Your Name</label>
        <input
          type={"text"}
          aria-label="Your Name"
          value={payload.sender}
          onChange={(e) => setName(e.target.value)}
        ></input>
        <!--Input to get sender email-->
        <label>Your Email</label>
        <input
          type={"email"}
          aria-label="Your Email"
          value={payload.email}
          onChange={(e) => setEmail(e.target.value)}
        ></input>
        <!--Textbox to get the message-->
        <label>Type in your message</label>
        <textarea
          rows={8}
          value={payload.message}
          onChange={(e) => setMessage(e.target.value)}
        ></textarea>
        <!--Button to trigger API call-->
        <button onClick={(e) => sendMessage(e)} className="send-button">
          Send Message
        </button>
      </div>
    </div>
  );
};

export default Contact;

В приведенном выше компоненте мы прослушиваем изменение полей ввода, используя событие onChange, и устанавливаем новые значения в состояние payload.

Проблема

Приведенный выше код вызывал проблему, когда я не мог ввести более одного символа.

Решение

Решение проблемы таково: в функции onClick вместо сохранения состояния во временной переменной, изменения значения во временной переменной и установки временной переменной в состояние, мы должны обновить состояние напрямую.

В нашем случае рассмотрим функцию setName. Функция должна быть изменена следующим образом:

const setName = (name) => {
    setPayload((prev) => ({
      ...prev,
      sender: name,
    }));
    checkCanSend();
  }

Теперь состояние обновляется напрямую, без каких-либо временных переменных.

Теперь мы можем печатать в поле ввода.

Окончательный код будет таким:

import { useState } from "react";
import callApi from "../axios/axios";
import "./contact.scss";
const Contact = () => {
  const initialClass = "form-input";
  const [payload, setPayload] = useState(payloadInitial);
  // Captures Sender name
  const setName = (name) => {
    setPayload((prev) => ({
      ...prev,
      sender: name,
    }));
    checkCanSend();
  };
  // Captures Email
  const setEmail = (email) => {
    setPayload((prev) => ({
      ...prev,
      email,
    }));
    checkCanSend();
  };
  // Captures Message
  const setMessage = (message) => {
    setPayload((prev) => ({
      ...prev,
      message,
    }));
    checkCanSend();
  };
  // Triggers API call on button click
  const sendMessage = (evt) => {
    evt.preventDefault();
    callApi
      .post("/email", payload)
      .then((res) => {
        console.log("Response: ", res)
      })
      .catch((err) => {
        console.error("Something went wrong: ", err)
      });
  };
  return (
    <div className="form-container">
      <h2 className="form-title">Write to me</h2>
      <div className="form-container">
        <!--Input to get sender name-->
        <label>Your Name</label>
        <input
          type={"text"}
          aria-label="Your Name"
          value={payload.sender}
          onChange={(e) => setName(e.target.value)}
        ></input>
        <!--Input to get sender email-->
        <label>Your Email</label>
        <input
          type={"email"}
          aria-label="Your Email"
          value={payload.email}
          onChange={(e) => setEmail(e.target.value)}
        ></input>
        <!--Textbox to get the message-->
        <label>Type in your message</label>
        <textarea
          rows={8}
          value={payload.message}
          onChange={(e) => setMessage(e.target.value)}
        ></textarea>
        <!--Button to trigger API call-->
        <button onSubmit={(e) => sendMessage(e)} className="send-button">
          Send Message
        </button>
      </div>
    </div>
  );
};

export default Contact;

Надеюсь, что это решение поможет решить проблему «Невозможно ввести текст в поле ввода». С нетерпением ждем ваших отзывов. Спасибо!

Первоначально опубликовано на https://sriram23.hashnode.dev.