0

I have a dynamically generated form which consists of individual components. The form may contain unlimited number of instances of each component. It is defined by map()ing an array.

// main.js
function submitHandler() {
    ...
}
...
<form onSubmint={submitHandler}>
    {formFields.map((item, index) => {
        {{
            'text': <UploadFormText name={someName} />,
            'image': <UploadFormImage name={someName} />,
            'video': <UploadFormVideo name={someName} />,
            'file': <UploadFormFile name={someName} />,
        }[item.type]}
    })}
</form>

Component itself consists of the main text field with value attribute and possible auxiliary elements. The value is changed by direct input or by other means and is then saved with useState() hook inside the component.

// component.js
export default function UploadFormText({ name }) {
    const [text, setText] = useState('')
    return (
        <>
            <input value={text} name={name} />
        </>
    )
}

How should I access value of component.js inside main.js to validate and submit it? If there are multiple ways, which is the most easy and which is the best practice?

Arctomachine
  • 401
  • 6
  • 12
  • you could pass it up as `props` by calling on a function on the main.js e.g `props.textFieldHandler(textValue)` from the component then on the main you have a function `const textFieldHandler = (val) => {setValue(val)}` or just simpy`useContext()` hook – otejiri May 24 '21 at 11:17
  • this may help you: https://stackoverflow.com/questions/42316604/how-to-implement-a-dynamic-form-with-controlled-components-in-reactjs – faramarz razmi May 24 '21 at 12:19
  • @faramarzrazmi I think this is more general guidelines about handling dynamic behavior, but it does not reflect the main problem. Which is how to extract value from the child component. – Arctomachine May 24 '21 at 13:22

1 Answers1

1

I would do it this way

// main.js
function submitHandler() {
    ...
}
function getValue(value){                  //fn that gets the value.
    console.log(value);
}

<form onSubmit={submitHandler}>
    {formFields.map((item, index) => {
        {{
            'text': <UploadFormText getValue={getValue} name={someName} />,
            'image': <UploadFormImage name={someName} />,
            'video': <UploadFormVideo name={someName} />,
            'file': <UploadFormFile name={someName} />,
        }[item.type]}
    })}
</form>

And pass it down as props like this

// component.js
export default function UploadFormText({ name, getValue }) {
    const [text, setText] = useState('')
    return (
        <>
            <input onChange={getValue} value={text} name={name} />
        </>
    )
}
shaswat.dharaiya
  • 381
  • 4
  • 13
  • It works fine with minimal adaptation. I wrap `onChange` in my custom function in which I call `getValue({name, value})`. Before asking this question I also thought: "What if I could pass a function? Wait, a function? No way it's possible". So it is. – Arctomachine May 24 '21 at 13:19