Some additional notes.
The sample code generated by forge create uses @atlaskit for form construction.
For the form itself, it uses Form which contains the properties formProps, dirty and submitting.
For each input field, it uses a Field that encapsulates other controls like TextField.
The way Field and TextField are designed, I found that I cannot specify my own id or key attribute. Field provides a name attribute that is passed down to TextField.
The result is for all the dynamically added rows, the TextField will all point to the same state variable, so they will all share the same value.
If I remove Field and use TextField directly, it will work, but the Form’s dirty flag will remain false even after editing the values.
The workaround is to give each Field a unique name, e.g. Name1, Name2, …, instead of expecting a single Name with an array of values. Then handle that accordingly in onSubmit().
Another issue is the dirty property of the Form. I have to add another state variable, default to false and set to true if rows are added/removed, then enable/disable the submit button based on that along with dirty and submitting.
Yet another issue is onChange event. ReactJS allows either using defaultValue, or value + onChange. If I need to do something on change, I can only use the later option. In the onChange handler I must update the state, but that messes with how Form handles the dirty flag, if the state is updated by onChange, dirty will be false. So as a workaround I have to use my own state variable (turn it on in onChange), but that means losing the ability to disable submit if the fields have been reverted to original values.