Dynamic Forms Dynamic Form Fields

Last updated: 2026-11-02

Dynamic Forms Dynamic Form Fields

When the number of fields is not fixed, drive the rendering from an array kept in state: each field stores one record, adding and removing fields means adding and removing array items, and updating a single field means mapping over the array and replacing the entry with a matching id. With stable keys, React then reuses the input state of each row correctly. The array is the single source of truth, so add, edit and remove are three small pure updates rather than three separate pieces of state to reconcile.

GroupComponent Patterns
KindPattern

ℹ️ Info The editor transpiles JSX to JavaScript and renders the real UI in a sandbox; components mount automatically — no manual render call needed.

📝 Syntax

const [rows, setRows] = useState([{ id: 1, name: '' }])

setRows([...rows, { id: nextId(), name: '' }])              // add a row
setRows(rows.filter(r => r.id !== id))                      // remove a row
setRows(rows.map(r => r.id === id ? { ...r, name: v } : r)) // edit one cell

Returns:No return value; this entry describes an encoding pattern rather than a function.

▶ Example

The example runs out of the box: it auto-renders when expanded, and edits take effect instantly.

Output:

One input row by default; clicking "+ Add row" appends a row and "Remove" deletes one, each row keeps its own input, and the count at the bottom updates in real time.

💡 Key Points

💡 Tip Key list rows by a business id instead of the array index, otherwise removing a middle row shifts the indexes and the inputs of the other rows get mixed up.
ℹ️ Info Keep array updates immutable: filter and map return new arrays, which is how React notices the change and re-renders.
⚠️ Warning Remember type="button" on the add and remove buttons inside a form, otherwise they trigger the default submit behaviour of the form.
More case studies coming soon.

📚 Related Tutorials

❓ FAQ

Q After deleting a row the values of the other rows get mixed up. Why?
A The key was the array index: after the deletion the indexes shift and React hands the input to the wrong record. Use a stable business id as the key.
Q Should each row get its own useState?
A No. The number of rows changes dynamically, so one array state with immutable per-id updates is simplest — and the number of hooks can never change anyway.
Q What should I use to generate the id of a new row?
A Date.now(), an incrementing counter or crypto.randomUUID() all work, as long as the id stays unique and stable within the same list.
Web-Tutorial.com

Web-Tutorial Tech Team

A team of developers maintaining programming tutorials. Each tutorial is written and reviewed by developers with expertise in that field. We work to keep our content accurate and reliable — if you spot an issue, please let us know.

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏