0

Inside this codepen there is React application that renders list of ToDo's. It uses .map() index parameter as key values to render this list.

I've added few items there after initial load and then I see this:

enter image description here

Then I sort it by date and type something into first item

enter image description here

Then I click on Sort by Latest and get this:

enter image description here

Question: Why React doesn't alter the position of <input> with text after pressing Sort by Latest button - can you elaborate algorithm or sequence of events that took place after button press?

N.B. And yes - I know that using .map() index is the source of this behaviour, so please don't suggest changing key property here to something meaningful. This example is good as describes my question correctly.

P.S. This is a spin off to this question, that asks about different thing.

zmii
  • 4,123
  • 3
  • 40
  • 64

1 Answers1

1

Because react uses the key to infer identity of the row, if you update all fields except key, react will see this as you are updating data but the row stays stationary, on the other extreme, if you only change the keys but keep all the data the same React will see the row as moved.

So the problem is using index as a key, you are telling react that the value you type in the input box belongs on whatever todo is on row 1 as that is the key prop its given, when working with sortable lists, the key should be something unique to that piece of data. If you instead do

<ToDo key={todo.id} {...todo} />

You are telling react that the input belongs to a specific todo.id and then you have an identifier that will move when sorted.

Think about the rendered DOM.

first we have (some tags ommited).

<li><input value="this is my input text" /></li>
<li><input value="this is my second input text" /></li>

Then after sorting we have

<li><input value="this is my second input text" /></li>
<li><input value="this is my input text" /></li>

You cannot tell from this alone if the list order has changed, or if the values in the input fields has changed, to get around this problem React made a convention of always checking the key property and let that tell it if a row is changed or moved, which give us:

<li key=1><input value="this is my input text" /></li>
<li key=2><input value="this is my second input text" /></li>

Then after sorting we have

<li key=2><input value="this is my second input text" /></li>
<li key=1><input value="this is my input text" /></li>

But if we just change the texts we get:

<li key=1><input value="this is my second input text" /></li>
<li key=2><input value="this is my input text" /></li>

which is now obvious whats a move and whats an edit.

krs
  • 4,096
  • 19
  • 22
  • So React has some mechanism of handling non-controlled inputs inside arrays of JSX? How does it know that this data inside input is linked to some element? – zmii Feb 27 '18 at 12:55
  • @zmii I think in your `ToDo` component needs a bit more complexity with regards to capturing the data of your `` and applying that change data to the `row` data structure. – Francis Leigh Feb 27 '18 at 12:57
  • It knows because the input-value is part of the tag. – krs Feb 27 '18 at 13:04