Skip to content

Commit

Permalink
move reconciliation index as keys examples from codepen into ./examples
Browse files Browse the repository at this point in the history
  • Loading branch information
ajcumine committed Nov 17, 2017
1 parent ae71605 commit ee6f792
Show file tree
Hide file tree
Showing 3 changed files with 207 additions and 1 deletion.
2 changes: 1 addition & 1 deletion content/docs/reconciliation.md
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ As a last resort, you can pass item's index in the array as a key. This can work

There can also be issues with the state of a component in a list if indexes are used as keys. The state of an item in a list (or any deep state inside of it) will stay attached to the original position of the item, even if the item has “moved” in the data source. This is particularly noticeable with inputs retaining their values in the original positions even when their parent components reorder or are prepended to.

[Here](http://codepen.io/ajcumine/pen/KmVWmQ?editors=0010) is an example of the issues that can be caused by using indexes as keys on CodePen, and [here](https://codepen.io/ajcumine/pen/ZKQeJM?editors=0010) is a updated version of the same example showing how not using indexes as keys will fix these reordering, sorting, and prepending issues.
[Here](codepen://reconciliation/index-used-as-key) is an example of the issues that can be caused by using indexes as keys on CodePen, and [here](codepen://reconciliation/no-index-used-as-key) is a updated version of the same example showing how not using indexes as keys will fix these reordering, sorting, and prepending issues.

## Tradeoffs

Expand Down
103 changes: 103 additions & 0 deletions examples/reconciliation/index-used-as-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const ToDo = (props) => (
<tr>
<td><label>{props.id}</label></td>
<td><input/></td>
<td><label>{props.createdAt.toTimeString()}</label></td>
</tr>
);

class ToDoList extends React.Component {
constructor() {
super();
const date = new Date();
const todoCounter = 1;
this.state = {
todoCounter: todoCounter,
list: [
{ id: todoCounter, createdAt: date },
]
}
}

sortByEarliest() {
const sortedList = this.state.list.sort((a, b) => {
return a.createdAt - b.createdAt;
});
this.setState({
list: [...sortedList]
})
}

sortByLatest() {
const sortedList = this.state.list.sort((a, b) => {
return b.createdAt - a.createdAt;
});
this.setState({
list: [...sortedList]
})
}

addToEnd() {
const date = new Date();
const nextId = this.state.todoCounter + 1;
const newList = [
...this.state.list,
{ id: nextId, createdAt: date }
];
this.setState({
list: newList,
todoCounter: nextId
});
}

addToStart() {
const date = new Date();
const nextId = this.state.todoCounter + 1;
const newList = [
{ id: nextId, createdAt: date },
...this.state.list
];
this.setState({
list: newList,
todoCounter: nextId
});
}

render() {
return(
<div>
<code>key=index</code><br/>
<button onClick={this.addToStart.bind(this)}>
Add New to Start
</button>
<button onClick={this.addToEnd.bind(this)}>
Add New to End
</button>
<button onClick={this.sortByEarliest.bind(this)}>
Sort by Earliest
</button>
<button onClick={this.sortByLatest.bind(this)}>
Sort by Latest
</button>
<table>
<tr>
<th>ID</th><th></th><th>created at</th>
</tr>
{
this.state.list.map((todo, index) => (
<ToDo
key={index}
{...todo}
/>
))
}
</table>
</div>
)
}
}

ReactDOM.render(
<ToDoList />,
document.getElementById('root')
);
103 changes: 103 additions & 0 deletions examples/reconciliation/no-index-used-as-key.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
const ToDo = (props) => (
<tr>
<td><label>{props.id}</label></td>
<td><input/></td>
<td><label>{props.createdAt.toTimeString()}</label></td>
</tr>
);

class ToDoList extends React.Component {
constructor() {
super();
const date = new Date();
const toDoCounter = 1;
this.state = {
list: [
{ id: toDoCounter, createdAt: date },
],
toDoCounter: toDoCounter
}
}

sortByEarliest() {
const sortedList = this.state.list.sort((a, b) => {
return a.createdAt - b.createdAt;
});
this.setState({
list: [...sortedList]
})
}

sortByLatest() {
const sortedList = this.state.list.sort((a, b) => {
return b.createdAt - a.createdAt;
});
this.setState({
list: [...sortedList]
})
}

addToEnd() {
const date = new Date();
const nextId = this.state.toDoCounter + 1;
const newList = [
...this.state.list,
{ id: nextId, createdAt: date }
];
this.setState({
list: newList,
toDoCounter: nextId
});
}

addToStart() {
const date = new Date();
const nextId = this.state.toDoCounter + 1;
const newList = [
{ id: nextId, createdAt: date },
...this.state.list
];
this.setState({
list: newList,
toDoCounter: nextId
});
}

render() {
return(
<div>
<code>key=id</code><br/>
<button onClick={this.addToStart.bind(this)}>
Add New to Start
</button>
<button onClick={this.addToEnd.bind(this)}>
Add New to End
</button>
<button onClick={this.sortByEarliest.bind(this)}>
Sort by Earliest
</button>
<button onClick={this.sortByLatest.bind(this)}>
Sort by Latest
</button>
<table>
<tr>
<th>ID</th><th></th><th>created at</th>
</tr>
{
this.state.list.map((todo, index) => (
<ToDo
key={todo.id}
{...todo}
/>
))
}
</table>
</div>
)
}
}

ReactDOM.render(
<ToDoList />,
document.getElementById('root')
);

0 comments on commit ee6f792

Please sign in to comment.