Home > database >  Updating list from child component react hooks
Updating list from child component react hooks

Time:06-20

I'm pretty new to react and I'm trying to update a list from a child component based on user input add it will not update correctly. The idea is the user is able to add multiple different bikes in one form, each with a type and an ageRange property. When the user clicks an "Add Bike" button it adds BikeInput component (which works fine) and is supposed to be adding a new empty bike to a list of bikes that will be sent when the form is submitted. I console logged in a useEffect function the list of bikes after adding a new input and that works okay, but when I try to set one of the new bikes it removes all the elements from the list except the first. Again I'm pretty new to react so I'm not exactly sure if I'm using the useEffect function correctly or if there's another way to go about this, but if you could let me know that'd be amazing.

Here's some snippets of the important parts of the code that relate to the type property since the ageRange should work the same way

Parent Component:

import { useState, useEffect } from 'react'

const initialList = {
    "id": 0,
    "type": "",
    "ageRange": ""
};

function Donate() {

    const [bikes, setBikes] = useState([initialList]);
    useEffect(() => console.log(bikes), [bikes])

    const setBikeType = (bikeType, bikeIndex) => {
        const updateBikes = bikes.map((bike) => {
            if (bike.id == bikeIndex) {
                bike.type = bikeType;
            }
            return bike;
        });
        setBikes(updateBikes);
    }

    const [bikeInputs, setBikeInputs] = useState([
        <BikeInput
            setBikeType={setBikeType}
            setBikeAgeRange={setBikeAgeRange}
            bikeIndex={0} />]);

    const addBikeForm = (e) => {
        e.preventDefault();
        var newBikeIndex = bikeInputs.length;
        setBikeInputs(bikeInputs =>
            [...bikeInputs,
                <BikeInput
                    setBikeType={setBikeType}
                    setBikeAgeRange={setBikeAgeRange}
                    bikeIndex={newBikeIndex}
                />
            ]
        );

        var newBikeId = bikes[bikes.length - 1].id   1;
        setBikes(bikes => [...bikes, { "id": newBikeId, "type": "", "ageRange": "" }]);

    };

    return (
        <div className="bike-form-container donate-form-one">
            ...             
            <p className="input-title">Bike Info.</p>
            {bikeInputs.map((item, i) => (
                <div className="bike-input" key={i}>{item}</div>
            ))}
            <button className="add-bike-btn" onClick={addBikeForm}>
                <i ></i> Add A Bike
            </button>
            ...
        </div>
    )
}

export default Donate

Child Component (BikeInput):

function BikeInput(props) {
    return (
        <div className="input-container">
            <select className="form-dropdown text-input"
                defaultValue="Type"
                onChange={e => props.setBikeType(e.target.value, props.bikeIndex)} >
                <option disabled>Type</option>
                <option value="Mountain"> Mountain </option>
                <option value="Road"> Road </option>
                <option value="Cruiser"> Cruiser </option>
                <option value="Hybrid"> Hybrid </option>
                <option value="Three Wheel"> Three Wheel (Tricycle) </option>
            </select>
            ...
        </div>
   )
}

export default BikeInput

CodePudding user response:

Remove your bikeInputs state, since you don't have to keep a collection of BikeInputs components. Just use the BikeInput component inside bikes.map to render each bike select option.

Please simplify and update your Donate component code as follows:

export function Donate() {
  const [bikes, setBikes] = useState([initialList]);

  useEffect(() => console.log(bikes), [bikes]);

  const setBikeType = useCallback(
    (bikeType, bikeIndex) => {
      const updateBikes = bikes.map((bike) => {
        if (bike.id === bikeIndex) {
          bike.type = bikeType;
        }
        return bike;
      });
      setBikes(updateBikes);
    },
    [bikes]
  );

  const addBikeForm = useCallback(
    (e) => {
      e.preventDefault();
      setBikes((bikes) => {
        const newBikeId = bikes[bikes.length - 1].id   1;
        return [...bikes, { id: newBikeId, type: "", ageRange: "" }];
      });
    },
    [setBikes]
  );

  return (
    <div className="bike-form-container donate-form-one">
      <p className="input-title">Bike Info.</p>
      {bikes.map((item, i) => (
        <div className="bike-input" key={i}>
          <BikeInput bikeIndex={i} setBikeType={setBikeType} />
        </div>
      ))}
      <button className="add-bike-btn" onClick={addBikeForm}>
        <i className="fa-solid fa-circle-plus"></i> Add A Bike
      </button>
    </div>
  );
}
  • Related