Blog

Part 8 · Lists and Keys in React

Turn an array into a list with map, and give each item a key. Learn why React needs keys, the bug that index keys cause, and how a key can reset a component.

In Part 1 you saw that an array shows each of its items on the page. In Part 5 you used items.map(...) to make one <li> for each item, and you gave each one key={item.id}. We promised to explain that key.

This part does that. First we turn an array of data into a list. Then we look at what a key is, and why React asks for one. We’ll see a real bug that a bad key causes, and how to pick a good key. At the end, we use a key to make a component start fresh.

Try this first

Read this code. Don’t press Run yet.

export default function App() {
  const fruits = ['Apple', 'Banana', 'Cherry']

  return (
    <ul>
      {fruits.map(fruit => <li>{fruit}</li>)}
    </ul>
  )
}

Make a guess. Will the three fruits show on the page? And will React say anything about this code?

Now press Run, and look at the Console under the result.

The list shows all three fruits. But React also prints this warning:

Each child in a list should have a unique "key" prop.

Check the render method of `App`. See https://react.dev/link/warning-keys for more information.

React prints these warnings only in development. A production build stays silent, but the bug is still there.

So the code works, but React wants one more thing from it. To see what, we first need to understand how the list was made.

From an array to a list: map

map is a method that every JavaScript array has. A method is a function that belongs to an object. map calls your function once for each item. It collects the answers into a new array, in the same order.

const doubled = [1, 2, 3].map(n => n * 2)
// doubled is [2, 4, 6]

The old array doesn’t change. map always makes a new one.

In “Try this first”, the function was fruit => <li>{fruit}</li>. It gets one fruit and returns one <li> element. So map made a new array of three <li> elements. As Part 1 showed, when you put an array inside { }, React shows each of its items, one after another.

Real data is usually an array of objects, not of plain text. Each object often has an id: a number or text that is different for every item. Here is a shopping list:

type Item = { id: number; name: string }

export default function App() {
  const items: Item[] = [
    { id: 1, name: 'Milk' },
    { id: 2, name: 'Bread' },
    { id: 3, name: 'Eggs' },
  ]

  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  )
}

Run it. The list shows, and the Console stays empty. The key made the warning go away.

When there are no { } right after =>, an arrow function returns the value after the arrow. You don’t need the word return. The ( ) around the <li> only group it, so it can go on its own line. You will see this shape very often.

map also gives your function a second value: the item’s position in the array. This position is called the index. It starts at 0. You can use it to number the items:

export default function App() {
  const items = [
    { id: 1, name: 'Milk' },
    { id: 2, name: 'Bread' },
    { id: 3, name: 'Eggs' },
  ]

  return (
    <ul>
      {items.map((item, index) => (
        <li key={item.id}>
          {index + 1}. {item.name}
        </li>
      ))}
    </ul>
  )
}

Showing the index on the page is fine. Using it as the key can cause a bug. We’ll see why soon.

What a key is

A key is a special attribute you give to each item in a list. Its value is a string or a number. It must be different for each item in that list. It names the item, so React can tell it apart from the others.

The key is stored on the element itself, next to type and props. We checked with React 19.3: for <li key="Apple">, the element’s key is "Apple". A number becomes text, so key={7} gives a key of "7". With no key, the element’s key is null.

The key is not one of the props. React uses it for its own work, and doesn’t pass it to your component. We’ll come back to that.

Why React needs keys

Lists change. People add items, remove them, and sort them. Each time, your component runs again and returns a new array of elements.

As Part 1 said, React then compares the new elements with the old ones. It changes only what is different. For a list, that means React must decide one thing for each new item: which old item is this?

The key answers that question. React matches each new item to the old item with the same key. When it finds a match, it keeps what belongs to that item:

  • the item’s tag on the page, with anything the user typed or checked in it;
  • the item’s component, with its state: what it remembers between renders (Part 4 explains state).

Old items with no match are removed, with their state. New keys get new items.

Without a key, React has nothing to match by except the position. So it matches the first new item with the first old item, the second with the second, and so on. React’s docs say that if you don’t give a key, React will use the index. That works until items are added, removed or moved.

An everyday example

Think of a teacher who keeps notes about each student. If she keeps the notes by seat number, adding a new student is a problem. The new student sits in seat 1, and everyone else moves down one seat. Now the note for seat 1 is about the wrong child.

If she keeps the notes by each child’s student number, nothing goes wrong. The notes stay with the right child, wherever the child sits. The index is the seat number. A good key is the student number.

The exact version

React matches by key only among the items of one list. It also checks that the type is the same, for example the same component. And “keeps” has an exact meaning. The component is not made again, so its state stays. The tag on the page is the same tag, moved if needed. React still renders the item again, and its props can change. Part 18 covers this matching in depth.

The index-as-key bug

Now let’s see what goes wrong with the index. In this list, each row is a Row component. Each Row keeps its own note in state. The list uses key={index}.

import { useState } from 'react'

type Person = { id: number; name: string }

let nextId = 4

function Row({ name }: { name: string }) {
  const [note, setNote] = useState('')
  return (
    <li>
      {name}:{' '}
      <input
        aria-label={'Note for ' + name}
        value={note}
        onChange={e => setNote(e.target.value)}
      />
    </li>
  )
}

export default function App() {
  const [people, setPeople] = useState<Person[]>([
    { id: 1, name: 'Ana' },
    { id: 2, name: 'Ben' },
    { id: 3, name: 'Cara' },
  ])

  function addZoe() {
    setPeople([{ id: nextId++, name: 'Zoe' }, ...people])
  }

  return (
    <div>
      <button onClick={addZoe}>Add Zoe at the top</button>
      <ul>
        {people.map((person, index) => (
          <Row key={index} name={person.name} />
        ))}
      </ul>
    </div>
  )
}

nextId gives each new person a new id: 4, then 5, and so on. {' '} adds a space after the :. [{ ... }, ...people] makes a new array with Zoe first (Part 5 explains this way of adding).

Press Run. Type “likes tea” into Ana’s box. Make a guess: when you add Zoe at the top, which row will say “likes tea”?

Now click “Add Zoe at the top”.

Zoe’s row says “likes tea”. Ana’s box is empty. The note stayed in the top row, and the names moved under it.

Here is why. Before the click, Ana had index 0, so her row had key 0. After the click, Zoe is first, so Zoe has index 0. React sees key 0 in both lists and thinks it is the same row. It keeps that row’s state, the note “likes tea”, and only changes its name to Zoe. Ana now has key 1, so she gets the row that was Ben’s.

Press Edit. Change key={index} to key={person.id} and run it again. Type into Ana’s box and add Zoe. Now Ana keeps her note, and Zoe’s box is empty. Ana’s key is 1 before and after, so React keeps her row and moves it down. React adds a new row, for key 4, at the top.

We tested three changes to this list with React 19.3, with “likes tea” typed into Ana’s box first:

Change With key={person.id} With key={index}
Add Zoe at the top Ana keeps “likes tea” Zoe shows “likes tea”
Remove Ana the note goes away with Ana Ben shows “likes tea”
Reverse the list Ana keeps it, now at the bottom Cara shows “likes tea”

The results were the same with Strict Mode on and off. With no key at all, the results matched key={index} exactly, and React printed the warning too.

This is not only about state. We tried two more lists with key={index} and added Zoe at the top. In the first list, the boxes did not use state, so the typed text lived only on the page. In the second list, each row had a checkbox: a small box you click to check it. We checked Ana’s box. Both times, Zoe’s row got Ana’s text, or Ana’s checked box. That was true with Strict Mode on and off.

Here is the same bug again, this time when the list is reversed. Choose a kind of key, then step through it.

1. Each row keeps its own note in state. Ana's says likes tea. 2. You click Reverse. The array is now Cara, Ben, Ana. 3. React matches old and new rows by key. Key 1 is still Ana. 4. So Ana's row moves to the bottom, and its note goes with it. 5. Right: the note is still next to Ana. key name note box (the row's own state) keyAnalikes tea keyBen keyCara people: Ana, Ben, Cara verdict

Reverse a list, with two kinds of key. Choose one, then press play or step through it.

  1. Each row keeps its own note in state. Ana’s box says “likes tea”.
  2. You click a button that reverses the list. The array is now Cara, Ben, Ana.
  3. React matches old rows and new rows by key.
  4. With key={person.id}, Ana’s key is 1 before and after. So React moves her row to the bottom, and the note moves with it. With key={index}, key 0 now belongs to Cara. So no row moves. React changes the names in place.
  5. With the id, the note is still next to Ana. With the index, Cara’s row shows Ana’s note.

When is the index safe?

In our test, adding Zoe at the end with key={index} caused no bug. Ana kept her note, because her index did not change. But the table above shows that removing an item breaks it, and so does a new order. Filtering does too, because it removes items from the array you show.

The index is safe when items are never added, removed or moved, except at the end. And the bug needs something the rows remember: state, typed text or a checked box. When the rows remember nothing, a wrong match costs only extra work, not a wrong page. Both of these are hard to promise as an app grows. React’s docs say index keys “often” lead to “subtle and confusing bugs”. If your data has an id, use it.

What makes a good key

A good key has three things.

  • It comes from the data. Data from a database already has an id for each item. If you make the items yourself, give each new item an id when you make it. React’s docs suggest a counter, like nextId above, or crypto.randomUUID(). That is a browser function that makes a long random id.
  • It doesn’t change. The same item must get the same key every time the component runs.
  • It is different from the other items in the same list. If two items share a key, React can’t tell them apart.

The second rule means you must never make a new value for the key while rendering. Read it from the data. Look at what key={Math.random()} does. Math.random() gives a new random number each time it runs.

import { useState } from 'react'

function Row({ name }: { name: string }) {
  const [note, setNote] = useState('')
  return (
    <li>
      {name}:{' '}
      <input
        aria-label={'Note for ' + name}
        value={note}
        onChange={e => setNote(e.target.value)}
      />
    </li>
  )
}

export default function App() {
  const [clicks, setClicks] = useState(0)
  const people = [
    { id: 1, name: 'Ana' },
    { id: 2, name: 'Ben' },
    { id: 3, name: 'Cara' },
  ]

  return (
    <div>
      <button onClick={() => setClicks(clicks + 1)}>Clicks: {clicks}</button>
      <ul>
        {people.map(person => (
          <Row key={Math.random()} name={person.name} />
        ))}
      </ul>
    </div>
  )
}

Run it. Type “likes tea” into Ana’s box. Then click the “Clicks” button.

Ana’s note is gone. The click made App run again, so every row got a new random key. No new key matched an old one. So React removed all three rows, with their state, and made three new ones.

Typing didn’t cause this. Typing changes only Ana’s Row, and App doesn’t run again. The click is what made App run.

We measured this with Strict Mode off. After the click, 0 of the 3 old <li> tags were still on the page, and all 3 Row components were made again. With key={person.id}, all 3 tags stayed, and Ana’s note stayed too. React printed no warning for the random keys. The code looks fine, so this bug is easy to miss.

Keys only need to be different among siblings

Siblings are elements with the same parent, like the <li> items inside one <ul>. A key only has to be different from its siblings. Two different lists can use the same keys.

export default function App() {
  const fruits = [{ id: 1, name: 'Apple' }, { id: 2, name: 'Banana' }]
  const vegetables = [{ id: 1, name: 'Carrot' }, { id: 2, name: 'Pea' }]

  return (
    <div>
      <ul>{fruits.map(f => <li key={f.id}>{f.name}</li>)}</ul>
      <ul>{vegetables.map(v => <li key={v.id}>{v.name}</li>)}</ul>
    </div>
  )
}

Both lists use the keys 1 and 2. React prints no warning. React’s docs say this is fine, as long as the keys are in different arrays.

Keys are not props

As Part 3 showed, a component can’t read its own key. Say Item tries to show it:

function Item(props: { name: string }) {
  return <li>{props.name}: {props.key}</li>
}

export default function App() {
  return (
    <ul>
      <Item key="a" name="Apple" />
    </ul>
  )
}

In an editor that checks TypeScript, this is an error: “Property ‘key’ does not exist”. The playground doesn’t check types, so it runs. props.key is undefined, so nothing shows after “Apple:”. And in development, React prints this warning:

Item: `key` is not a prop. Trying to access it will result in `undefined` being returned. If you need to access the same value within the child component, you should pass it as a different prop. (https://react.dev/link/special-props)

We checked: taking it out with function Item({ key, name }) gives the same warning, and undefined too.

The fix is in the warning. If the child needs the value, pass it again under another name:

function Item({ id, name }: { id: string; name: string }) {
  return <li>{name}: {id}</li>
}

export default function App() {
  return (
    <ul>
      <Item key="a" id="a" name="Apple" />
    </ul>
  )
}

It looks like saying the same thing twice. But the two have different jobs. The key is for React. The id is for your component.

Several tags for each item: Fragment with a key

Sometimes each item needs two tags, not one. A word list on a page can use <dl>. Each word goes in a <dt> tag, and its meaning in a <dd> tag.

The function inside map must return one value. That is Part 1’s rule of one parent tag. And the key needs a place to go. As Part 1 showed, a Fragment groups tags without adding anything to the page. But the short form <> has no place to write a key. So you write the long form, <Fragment>, and bring it in from react:

import { Fragment } from 'react'

const words = [
  { id: 1, word: 'Cat', meaning: 'A small pet that says meow.' },
  { id: 2, word: 'Dog', meaning: 'A pet that barks.' },
]

export default function App() {
  return (
    <dl>
      {words.map(w => (
        <Fragment key={w.id}>
          <dt>{w.word}</dt>
          <dd>{w.meaning}</dd>
        </Fragment>
      ))}
    </dl>
  )
}

The page gets only the <dt> and <dd> tags. The Fragment adds nothing. When we removed key={w.id}, React printed the same “unique key” warning as before.

Filter, then map

Often you want to show only some items. JavaScript’s filter method makes a new array with only the items that pass a test. Then map turns those items into elements.

type Todo = { id: number; text: string; done: boolean }

export default function App() {
  const todos: Todo[] = [
    { id: 1, text: 'Feed the cat', done: true },
    { id: 2, text: 'Buy milk', done: false },
    { id: 3, text: 'Call Grandma', done: false },
  ]

  const left = todos.filter(todo => !todo.done)

  return (
    <ul>
      {left.map(todo => (
        <li key={todo.id}>{todo.text}</li>
      ))}
    </ul>
  )
}

!todo.done means “not done”. So left holds only the two tasks that are not done.

Notice the key. “Buy milk” is index 1 in todos, but index 0 in left. Mark a task as done, and the indexes in left change. The id never changes. This is one more reason to take the key from the data.

A list item component: where the key goes

As a list item grows, you often move it into its own component. Then you need to decide where the key goes.

Here is a common first try. The key is on the <li>, inside the new component:

type Todo = { id: number; text: string }

function TodoItem({ todo }: { todo: Todo }) {
  return <li key={todo.id}>{todo.text}</li>
}

export default function App() {
  const todos: Todo[] = [
    { id: 1, text: 'Feed the cat' },
    { id: 2, text: 'Buy milk' },
  ]

  return (
    <ol>
      {todos.map(todo => (
        <TodoItem todo={todo} />
      ))}
    </ol>
  )
}

Run it. The list shows, but the warning is back:

Each child in a list should have a unique "key" prop.

Check the render method of `App`. See https://react.dev/link/warning-keys for more information.

Look at the array map makes. Its items are <TodoItem> elements, not <li> elements. React matches the items of that array, so the key must be on them. The <li> inside TodoItem is not in a list at all. Each TodoItem returns just one.

The fix is to move the key to where the list is made:

type Todo = { id: number; text: string }

function TodoItem({ todo }: { todo: Todo }) {
  return <li>{todo.text}</li>
}

export default function App() {
  const todos: Todo[] = [
    { id: 1, text: 'Feed the cat' },
    { id: 2, text: 'Buy milk' },
  ]

  return (
    <ol>
      {todos.map(todo => (
        <TodoItem key={todo.id} todo={todo} />
      ))}
    </ol>
  )
}

The rule is short. The key goes on the outside tag that the function inside map returns. React’s docs put it this way: “JSX elements directly inside a map() call always need keys!”

Using a key to reset a component

Keys are not only for lists. You saw this in Part 7 with Ana’s and Ben’s counters, and in Part 4. A key works on any element or component. When the key changes, React treats it as a different component. It removes the old one, with its state, and makes a new one.

Forms are a common case. Here is a box for writing a note to a friend. Pick Ana, start a note, then switch to Ben:

import { useState } from 'react'

function NoteForm({ name }: { name: string }) {
  const [text, setText] = useState('')
  return (
    <label>
      Note to {name}:{' '}
      <input aria-label="Note" value={text} onChange={e => setText(e.target.value)} />
    </label>
  )
}

export default function App() {
  const [to, setTo] = useState('Ana')

  return (
    <div>
      <button onClick={() => setTo('Ana')}>Ana</button>
      <button onClick={() => setTo('Ben')}>Ben</button>
      <NoteForm key={to} name={to} />
    </div>
  )
}

Run it. Type “see you at 5”, then click “Ben”. The box is empty. It’s a fresh note for Ben.

Now press Edit, remove key={to}, and try again. This time the text stays when you switch to Ben. NoteForm is in the same place with the same type, so React keeps it, and its state. Your note to Ana could go to Ben by mistake.

With key={to}, the key changes from "Ana" to "Ben". React makes a brand new NoteForm, so its state starts from '' again. We checked: the input box on the page was a new one, not the old one. React’s docs say you can “force a subtree to reset its state by giving it a different key”. A subtree is a component and everything inside it. Part 18 explains when React keeps state and when it doesn’t.

Do keys make React faster?

They can save work on the page. We showed 100 rows, then added one row at the top, with Strict Mode on.

  • With key={item.id}, React added 1 new <li>. It didn’t change the text in any of the 100 old rows.
  • With key={index}, React also added 1 new <li>, but at the end. Then it changed the text in all 100 old rows, because each row now had a different item.

So good keys can save work. But the bigger reason to use them is the bug above, not speed.

Common mistakes

Curly braces in map with no return

export default function App() {
  const fruits = ['Apple', 'Banana', 'Cherry']

  return (
    <ul>
      {fruits.map(fruit => {
        <li key={fruit}>{fruit}</li>
      })}
    </ul>
  )
}

In an editor that checks TypeScript, you get an error: Type 'void[]' is not assignable to type 'ReactNode'. void is TypeScript’s word for “this function returns nothing”. The playground doesn’t check types, so press Run. The list is empty, and React prints no error and no warning.

An arrow function with { } right after the arrow needs the word return. Without it, the function returns undefined. So map makes an array of three undefined values, and they show nothing. Fix it in one of two ways. Remove the { }, as in fruit => <li key={fruit}>{fruit}</li> (the ( ) are optional). Or write return <li key={fruit}>{fruit}</li> inside the curly braces.

Using the index as the key in a list that changes

This is the bug from the middle of this part. Items get added, removed, sorted or filtered, and state stays with the wrong row. Use an id from the data.

Two items with the same key

export default function App() {
  const fruits = ['Apple', 'Banana', 'Apple']

  return (
    <ul>
      {fruits.map(fruit => <li key={fruit}>{fruit}</li>)}
    </ul>
  )
}

Using the text itself as the key works only while no two items have the same text. Here “Apple” is there twice. The page still shows three items on the first render. But React prints this:

Encountered two children with the same key, `Apple`. Keys should be unique so that components maintain their identity across updates. Non-unique keys may cause children to be duplicated and/or omitted — the behavior is unsupported and could change in a future version.

“Unsupported” means React makes no promise about what happens. Give each item a real id.

Making the key while rendering

key={Math.random()}, or any key made fresh each time the component runs, throws away every row on every render. Make the id once, when you make the item, and keep it with the item.

Putting the key inside the list item component

The key goes on <TodoItem key={todo.id} /> where you call map, not on the <li> inside TodoItem.

Reading props.key in the child

It is undefined, and React warns. Pass the value again as a normal prop, like id.

Practice

Press Edit on any example above and try these.

  1. In “Try this first”, add a key so that the warning goes away.
  2. In the index-as-key example, keep key={index}. Change addZoe so it removes the first person instead: setPeople(people.slice(1)). Type “likes tea” into Ana’s box and click the button. Which row has the note now? Then change the key to key={person.id} and try again.
  3. In the first shopping list, under “From an array to a list”, add a field price to each item. Use filter to show only the items that cost less than 2.
  4. In the note form example, remove key={to}. Type “see you at 5”, then click “Ben”. What does the box show? Then put the key back.
Answers
  1. {fruits.map(fruit => <li key={fruit}>{fruit}</li>)}. Each fruit’s name is different, so the name works as a key here. Run it, and the Console stays empty.
  2. With key={index}, Ben’s row now shows “likes tea”. Ben has index 0, so he gets the row that was Ana’s. With key={person.id}, Ana’s row goes away with her note, and Ben’s and Cara’s boxes stay empty.
  3. For example: { id: 1, name: 'Milk', price: 1.5 }, and so on, with type Item = { id: number; name: string; price: number }. Then items.filter(item => item.price < 2).map(item => <li key={item.id}>{item.name}</li>). Keep item.id as the key.
  4. The box still shows “see you at 5”, next to “Note to Ben:”. Without a key, React keeps the same NoteForm and its state. With key={to} back, switching to Ben gives an empty box.

Interview questions

Try to answer each one out loud before you open the answer.

Why does React need a key on each item in a list?

When a list renders again, React compares the new items with the old ones. The key tells React which old item each new item is. Then React can keep that item’s state and its tags on the page, and move them if the order changed. It removes old items whose key is gone, and makes new items for new keys.

A strong answer adds that keys matter most when items are added, removed or sorted. It also says that without a key, React matches by position and prints a warning.

What goes wrong when you use the array index as the key?

The index belongs to the position, not to the item. If you add an item at the top, every item’s index changes. React then matches each old row with the wrong new item. So state stays in the old position, while the names change. In our test, a note typed for Ana showed up next to Zoe.

A strong answer adds that it’s not only state. Text typed into a box and a checked box also stay in the old position. It says when the index is safe: items are never added, removed or moved, except at the end. When the rows remember nothing, a wrong match costs only extra work. It also says that no key at all behaves the same as the index.

Why is key={Math.random()} a bad idea?

The key changes on every render, so no new key ever matches an old one. React removes every item and makes it again, each time the list renders. All state inside the items is lost, and typed text with it. It is also slower, because the tags on the page are made again. React prints no warning, so the bug is easy to miss.

A strong answer adds that Effects inside the items run again too, because each item is new. Effects come in Part 11. In our test, each row had an effect that runs when the row is made. After one click, all 3 ran again. It also gives the fix. Make the id once, when the item is created, with a counter or crypto.randomUUID(). Then store it with the item.

Can a component read its own key?

No. React keeps the key for itself and doesn’t pass it as a prop. props.key is undefined, and in development React warns that “key is not a prop”. If the child needs the value, pass it again as another prop: <Item key={id} id={id} />.

A strong answer adds three details. First, ref became a normal prop for function components in React 19, but key did not. Second, TypeScript stops you only when key is not in the props type. We checked: with props: { key?: string; name: string }, the code type-checks, and props.key is still undefined. Third, in development 'key' in props is true, because React adds a hidden check that prints the warning. Object.keys(props) still lists only the real props.

Must keys be unique in the whole app?

No. A key only has to be different from its siblings: the other items in the same list. Two separate lists can both use the keys 1, 2 and 3. If two siblings do share a key, React warns: “Encountered two children with the same key”.

A strong answer adds that keys work outside lists too. A key sets a child’s place within its parent. So <Counter key="Ana" /> and <Counter key="Ben" /> in one spot are two counters.

You move a list item into its own component. Where does the key go?

On the component, where map makes it: todos.map(todo => <TodoItem key={todo.id} todo={todo} />). React matches the items of the array that map returns, and those items are the <TodoItem> elements. A key on the <li> inside TodoItem doesn’t help, and React still warns.

A strong answer adds the Fragment case. When each item is several tags, wrap them in <Fragment key={id}>, because the short <> can’t take a key.

How can a key reset a component’s state?

Give the component a key that changes when you want it to start fresh, like <NoteForm key={friendId} />. When the key changes, React treats it as a different component. It removes the old one with its state and makes a new one. This is useful for a form that should be empty for each new person.

A strong answer names the cost. Everything inside is made again, including the tags on the page, and Effects run again. In our test, the form’s box was a new tag. An effect that runs when the form is made ran again on each switch. It also names the pattern to avoid: clearing the state in an effect when a prop changes. React’s docs mark that “Avoid”, because the component first renders with the old value and then renders again. A key clears every piece of state inside, with no extra code.

Sources

  • Rendering Lists, react.dev: map and filter, the key rules, where keys come from, index and Math.random() keys, keys are not props, and keys on Fragments.
  • Preserving and Resetting State, react.dev: using a key to reset a component, and resetting a form with a key.
  • You Might Not Need an Effect, react.dev: resetting all state when a prop changes, with a key.
  • Fragment, react.dev: only <Fragment> can take a key, not <>.
  • Special Props Warning, react.dev: why a component can’t read key.
  • createElement, react.dev: an element’s key.
  • The warnings, the element keys, the table of three changes, the random-key test, the 100-row test and the form test come from running React 19.3.0 for this post.

How useful was this post?

Click on a heart to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.