I’m trying to capture the inputs of dynamically created input fields and I’m only able to get the first set of exercise fields(Exercise, Reps, Sets)
import { useState } from "react"; export default StackTest; function StackTest() { const [formData, setFormData] = useState({ title: "", date: "", exercises: [{ Exercise: "benchpress", Reps: "5", Sets: "5" }], }); const handle = (e, type, index) => { setFormData({ title: formData.title, date: formData.date, exercises: [ { Exercise: type === "E" ? e : formData.exercises[index].Exercise, Reps: type === "R" ? e : formData.exercises[index].Reps, Sets: type === "S" ? e : formData.exercises[index].Sets, }, ], }); }; const updateForm = (e) => { setFormData((currentFormData) => ({ ...currentFormData, [e.target.name]: e.target.value, })); }; const handleAddExercise = (e) => { e.preventDefault(); setFormData((currentFormData) => { return { ...currentFormData, exercises: [ ...currentFormData.exercises, { Exercise: "benchpress", Reps: "5", Sets: "5" }, ], }; }); }; return ( <> <form action=""> <label htmlFor="">title</label> <input type="text" name="title" value={formData.title} onChange={updateForm} /> <label htmlFor="">date</label> <input type="text" name="date" value={formData.date} onChange={updateForm} /> {formData.exercises.map((exercise, index) => { return ( <div key={index}> <input placeholder="exercise" onChange={(e) => handle(e.target.value, "E", index)} /> <input placeholder="reps" onChange={(e) => handle(e.target.value, "R", index)} /> <input placeholder="sets" onChange={(e) => handle(e.target.value, "S", index)} /> <button onClick={handleAddExercise}>Add Exercise</button> </div> ); })} </form> </> ); }
Whenever I type in one of the added exercise fields it will just remove it after the first character. I also tried to add an if statement in the handle function to check if the index was the same but as I’m new to react and coding in general I may have implemented that wrong.
Advertisement
Answer
The issue is that you’re overwriting the contents of your exercises array when you need to create a copy of it and mutate it.
The simplest solution would be to create a copy of your Exercises array, make any mutations needed and then update your state.
import { useState } from "react"; export default StackTest; function StackTest() { const [formData, setFormData] = useState({ title: "", date: "", exercises: [{ Exercise: "benchpress", Reps: "5", Sets: "5" }], }); const handle = (e, type, index) => { let localExer = [ ...formData.exercises ]; localExer[index].Exercise = (type === "E" ? e : formData.exercises[index].Exercise) localExer[index].Reps = (type === "R" ? e : formData.exercises[index].Reps) localExer[index].Sets = (type === "S" ? e : formData.exercises[index].Sets) setFormData({ title: formData.title, date: formData.date, exercises: [ ...localExer], }); }; const updateForm = (e) => { setFormData((currentFormData) => ({ ...currentFormData, [e.target.name]: e.target.value, })); }; const handleAddExercise = (e) => { e.preventDefault(); setFormData((currentFormData) => { return { ...currentFormData, exercises: [ ...currentFormData.exercises, { Exercise: "benchpress", Reps: "5", Sets: "5" }, ], }; }); }; return ( <> <form action=""> <label htmlFor="">title</label> <input type="text" name="title" value={formData.title} onChange={updateForm} /> <label htmlFor="">date</label> <input type="text" name="date" value={formData.date} onChange={updateForm} /> {formData.exercises.map((exercise, index) => { return ( <div key={index}> <input placeholder="exercise" onChange={(e) => handle(e.target.value, "E", index)} /> <input placeholder="reps" onChange={(e) => handle(e.target.value, "R", index)} /> <input placeholder="sets" onChange={(e) => handle(e.target.value, "S", index)} /> <button onClick={handleAddExercise}>Add Exercise</button> </div> ); })} </form> </> ); }