I have an App with 2 inputs where you can choose 1 muscle and a number of exercices for this muscle.
I added an "Add" button to duplicates these inputs to add a new muscle to work with its number of exercices.
The problem is, when I change an input, all same inputs will change because they have the same key (I guess).
Anyone can show me how to solve this ?
Here is my code :
import { Formik, Form, Field } from "formik";
import React, { useState } from "react";
import { useNavigate } from "react-router-dom";
import { getAllMuscles, numberOfExercices } from "../helpers/dataModuler";
import { setInLocalStorage } from "../helpers/localStorageHandler";
export const ProgramForm: React.FC<{}> = () => {
const [numberOfMusclesInProgram, setNumberOfMusclesInProgram] = useState(1);
const navigate = useNavigate();
const listOfMuscles = getAllMuscles();
const initialValues = {
numberOfExercices: 0,
muscle: listOfMuscles[0]
};
const handleSubmit = (values: {}) => {
setInLocalStorage("program", values);
navigate("/programme");
};
return (
<>
<Formik
initialValues={initialValues}
onSubmit={(values) => handleSubmit(values)}
>
<Form>
<div id="container">
{[...Array(numberOfMusclesInProgram)].map((n, i) => (
<DisplayMuscleInProgram key={n} />
))}
</div>
<button
onClick={() =>
setNumberOfMusclesInProgram(numberOfMusclesInProgram + 1)
}
type="button"
className="rounded-md border"
>
Add
</button>
<div className="text-center">
<button
type="submit"
className="mt-8 rounded-lg bg-primary p-2 text-white"
>
Let's gooooo đź’Ş
</button>
</div>
</Form>
</Formik>
</>
);
};
export const DisplayMuscleInProgram = (props: { key: any }) => {
const listOfMuscles = getAllMuscles();
return (
<>
<div className="my-4 grid grid-cols-5 justify-between gap-5">
<Field
as="select"
className="col-span-3 rounded-lg bg-lightGray p-3"
name={`muscle-${props.key}`}
>
{listOfMuscles.map((muscle, key) => (
<option key={key}>{muscle}</option>
))}
</Field>
<Field
as="select"
className="col-span-2 rounded-lg bg-lightGray p-3"
name="numberOfExercices"
>
{numberOfExercices(10)}
</Field>
</div>
</>
);
};
>Solution :
In ProgramForm replace <div id="container" /> with the following (replacing n with i):
<div id="container">
{[...Array(numberOfMusclesInProgram)].map((n, i) => (
<DisplayMuscleInProgram key={i} />
))}
</div>
Alternatively, you may try:
<div id="container">
{[...Array(numberOfMusclesInProgram).keys()].map((n) => (
<DisplayMuscleInProgram key={n} />
))}
</div>
Source: https://stackoverflow.com/a/33352604/975164
Currently all your inputs have exactly the same name because of the following lines in DisplayMuscleInProgram:
<Field
as="select"
className="col-span-3 rounded-lg bg-lightGray p-3"
name={`muscle-${props.key}`} // this line
>
React docs recommend using someEntity.id as keys and warn against using indexes as keys when the order of list items is expected to change. However, in this case, I believe you will be safe.
As a side note: Since you are using Formik, I recommend using Formik’s built-in <FieldArray /> for this purpose i.e. add more inputs to the form on button click. You may read more about it here: https://formik.org/docs/api/fieldarray