lomine
lomine

Reputation: 1171

React form with useState for multiple values

I have a demo here

It's a simple react form with typescript

Is it possible to use useState to capture the input fields data when the fields are completed

The form isn't just one piece of data but 3 - username, password and email

I could do it for one value with

onChange={e => setContact(e.target.value)}

but can I do it for 3 separate values

Upvotes: 1

Views: 4828

Answers (3)

Louis Coulet
Louis Coulet

Reputation: 4591

You can do it using computed properties.
First add a name property to each of your input, with values "username", "password", "email", then:

onChange={e => setContact(contact => ({...contact, [e.target.name]: e.target.value}))}

Edit: in React versions before 17, events are pooled and setContact update function is running asynchronously, so the event needs to be persisted this way:

onChange={e => {
  e.persist();
  setContact(contact => ({...contact, [e.target.name]: e.target.value}));
}}

Upvotes: 1

user14361391
user14361391

Reputation:

You can create a object in the state and update the state with cloned object.

Here you go, Code with results as you expect:

import React, { useState } from "react";
import { render } from "react-dom";

import './style.css'

const App = () => {
  interface IFrom {
    username: string;
    password: string;
    email: string;
  }

  const [contact, setContact] = useState<IFrom[]>({
    username:"",
    email:"",
    password:"",
  });

  console.log(contact)

  const handelSubmit = () => 
  {

    axios.post(contact) //Example

  };

  return (
    <div>
      <form onSubmit={handelSubmit}>
        <div>
          <input
            type="text"
            placeholder="username"
            value={contact.usename}
            onChange={e => setContact({...contact, username: e.target.value})}
          />
        </div>
        <div>
          <input
            type="password"
            placeholder="password"
            onChange={e => setContact({...contact, password: e.target.value})}
          />
        </div>
        <div>
          <input
            type="email"
            placeholder="email"
            onChange={e => setContact({...contact, email: e.target.value})}
          />
        </div>
        <input className='submit' type="submi" value='submit'/>
      </form>
    </div>
  );
};

render(<App />, document.getElementById("root"));

Upvotes: 1

mbdavis
mbdavis

Reputation: 4010

Your handler could refer to the input name which you could then use to update the form object. There's a couple of issues with your syntax for this on the stackblitz - i.e the state object should be an object, not an array, so here's a full example:

const App = () => {
  interface IForm {
    username: string;
    password: string;
    email: string;
  }

  const [form, setFormValue] = useState<IForm>({
    username: "",
    password: "",
    email: ""
  });

  const updateForm = (
    formKey: keyof IForm,
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    const { value } = event.target;

    setFormValue({
      ...form,
      [formKey]: value
    });
  };

  const handelSubmit = () => {
    console.log("Form Submitted! Values: ", form);
  };

  return (
    <div>
      <form onSubmit={handelSubmit}>
        <div>
          <input
            type="text"
            placeholder="username"
            value={form.username}
            onChange={e => updateForm("username", e)}
          />
        </div>
        <div>
          <input
            type="password"
            placeholder="password"
            value={form.password}
            onChange={e => updateForm("password", e)}
          />
        </div>
        <div>
          <input
            type="email"
            placeholder="email"
            value={form.email}
            onChange={e => updateForm("email", e)}
          />
        </div>
        <input className="submit" type="submit" value="submit" />
      </form>
    </div>
  );
};

Upvotes: 1

Related Questions