Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Handle state when generate multiple forms on a button click

I’m trying to create something where a user can add multiple addresses, with a maximum of 3 and the default one which can’t be removed.

For this example, an address is just a street name and city.

What i’m struggling to figure out is how I can handle the state and the form input fields for this scenario.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I could have 3 separate states for each address and just target the state values in the forms that way, but I’d like to know if you guys have a cleaner approach to doing something like this.

And once the form is submitted, I would want an array of these addresses as they form part of another object in my use case.

Here’s the React code

import { useState } from "react";
import "./styles.css";

export default function App() {
  const [addressCount, setAddressCount] = useState(1);
  const [address, setAddress] = useState([]);

  const handleAddressChange = (event) => {
    const { name, value } = event.target;
    // handle address state
  };

  const addAddress = () => {
    if (addressCount == 3) {
      alert("you cannot more than 3 addresses");
      return;
    }
    setAddressCount(addressCount + 1);
  };

  const removeAddress = () => {
    if (addressCount == 1) {
      alert("You cannot remove this address");
      return;
    }
    setAddressCount(addressCount - 1);
  };

  const AddressDiv = (index) => {
    return (
      <div key={index} className="address-section">
        <div className="mb-2">
          <label>Street name</label>
          <input
            type="text"
            placeholder="Enter street name"
            name="streetName"
            onChange={handleAddressChange}
          />
        </div>
        <div className="mb-2">
          <label>City</label>
          <input
            type="text"
            placeholder="Enter city name"
            name="streetName"
            onChange={handleAddressChange}
          />
        </div>
        <div className="add-another-address-section mt-3 mb-4">
          <button type="button" onClick={addAddress}>
            + Add another
          </button>
          <button type="button" onClick={removeAddress}>
            - Remove
          </button>
        </div>
      </div>
    );
  };

  return (
    <div className="App">
      DIV COUNT {addressCount}
      <AddressDiv />
      {Array.from({ length: addressCount - 1 }, (_, index) => {
        return <div style={{ margin: "2rem" }}>{AddressDiv(index)}</div>;
      })}
    </div>
  );
}

And here’s a CodeSandbox link of what It roughly looks like.

https://codesandbox.io/p/sandbox/generate-div-8hknk3?file=%2Fsrc%2FApp.js%3A63%2C26

>Solution :

addressCount is redundant state and should be removed as it can always be computed from address (namely, address.length). The code can be simplified like so:

export default function App() {
  const [address, setAddress] = useState([{ id: 0 }]);
  const id = useRef(0);
  const addAddress = (insertAfter) => {
    if (address.length === 3) alert('you cannot more than 3 addresses');
    else
      setAddress(address.toSpliced(insertAfter + 1, 0, { id: ++id.current }));
  };
  const removeAddress = (index) => {
    if (index === 0) alert('You cannot remove this address');
    else setAddress(address.toSpliced(index, 1));
  };
  const handleChange = (event, index) => {
    setAddress(
      address.map((o, i) =>
        i !== index ? o : { ...o, [event.target.name]: event.target.value }
      )
    );
  };
  return (
    <div className="App">
      DIV COUNT {address.length}
      {address.map((o, index) => (
        <div key={o.id} className="address-section">
          <div className="mb-2">
            <label>Street name</label>
            <input
              type="text"
              placeholder="Enter street name"
              name="streetName"
              value={o.streetName}
              onChange={(e) => handleChange(e, index)}
            />
          </div>
          <div className="mb-2">
            <label>City</label>
            <input
              type="text"
              placeholder="Enter city name"
              name="cityName"
              value={o.cityName}
              onChange={(e) => handleChange(e, index)}
            />
          </div>
          <div className="add-another-address-section mt-3 mb-4">
            <button type="button" onClick={() => addAddress(index)}>
              + Add another
            </button>
            <button type="button" onClick={() => removeAddress(index)}>
              - Remove
            </button>
          </div>
        </div>
      ))}
    </div>
  );
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading