-1

I'm having trouble trying to get the data (exercise name, set number, weight, reps) that is inputted by the user after the Test components are rendered by pressing the "Add Exercise" button and updating the respective "Test" components within the exercises array that each set of form belongs to. I'm trying to return the exercises array such that it contains Test components with each component containing each set of the inputted information.

wellthen
  • 19
  • 1
  • 6
  • Does this answer your question? [How to pass data from child component to its parent in ReactJS?](https://stackoverflow.com/questions/38394015/how-to-pass-data-from-child-component-to-its-parent-in-reactjs) – Henry Woody Oct 28 '22 at 00:22
  • You need to store the state in the parent component and pass it to the children rather than the other way around. – Henry Woody Oct 28 '22 at 00:22
  • What would the state look like if it were initialized in the parent comp rather than the child? Sorry if I'm having a little trouble understanding! – wellthen Oct 28 '22 at 00:50

1 Answers1

1

Rather than retrieving the data to create an array, it's easier to start with the data as an array and the pass the data down. This means you need to move the state from the child (<Test>) component to the parent (<Popup>).

Luckily the structure of your code does not need to change too much.

Right now you have something like this (to simplify):

function Popup() {
    const [exercises, setExercises] = useState([]);

    const addExercise = () => {
        setExercises([...exercises, Test])
    }
    
    const removeExercise = (i) => {
        let data = [...exercises];
        data.splice(i,1);
        setExercises(data);
    }

    return (
        <div>
            <button onClick={addExercise}>Add Exercise</button>

            {exercises.map((item,i) => {
                return (
                    <div key={i}>
                        <button onClick={() =>removeExercise(i)}>Remove Exercise</button>
                        <Test/>
                    </div>
                )
            })}
        </div>
    )
}

function Test() {
    const [inputFields, setInputFields ] = useState([{setnumber: '', weight: '', rep: ''}])

    return <div>{/* render content */}</div>
}

Something like this is what you want:

function Popup() {
    const [exercises, setExercises] = useState([]);

    const addExercise = () => {
        // This is the main change, we store the data, not the component in state
        setExercises([...exercises, {setnumber: '', weight: '', rep: ''}]);
    }
    
    const removeExercise = (i) => {
        // Same logic as before, just changed to using a callback to get the current version of exercises
        setExercises(prev => {
            const data = [...prev];
            data.splice(i,1);
            return data;
        });
    }

    const setExercise = (index, value) => {
        setExercises(prev => prev.map((e, i) => i === index ? value : e));
    }

    return (
        <div>
            <button onClick={addExercise}>Add Exercise</button>

            {exercises.map((item,i) => {
                return (
                    <div key={i}>
                        <button onClick={() =>removeExercise(i)}>Remove Exercise</button>
                        <Test inputFields={item} setInputFields={(value) => setExercise(i, value)}/>
                    </div>
                )
            })}
        </div>
    )
}

// The `inputFields` and `setInputFields` props work exactly like those created from using `useState`
function Test({ inputFields, setInputFields }) {
    return <div>{/* render content */}</div>
}
Henry Woody
  • 14,024
  • 7
  • 39
  • 56