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.