Skip to content

Commit ee6f792

Browse files
committed
move reconciliation index as keys examples from codepen into ./examples
1 parent ae71605 commit ee6f792

File tree

3 files changed

+207
-1
lines changed

3 files changed

+207
-1
lines changed

content/docs/reconciliation.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ As a last resort, you can pass item's index in the array as a key. This can work
142142

143143
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.
144144

145-
[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.
145+
[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.
146146

147147
## Tradeoffs
148148

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
const ToDo = (props) => (
2+
<tr>
3+
<td><label>{props.id}</label></td>
4+
<td><input/></td>
5+
<td><label>{props.createdAt.toTimeString()}</label></td>
6+
</tr>
7+
);
8+
9+
class ToDoList extends React.Component {
10+
constructor() {
11+
super();
12+
const date = new Date();
13+
const todoCounter = 1;
14+
this.state = {
15+
todoCounter: todoCounter,
16+
list: [
17+
{ id: todoCounter, createdAt: date },
18+
]
19+
}
20+
}
21+
22+
sortByEarliest() {
23+
const sortedList = this.state.list.sort((a, b) => {
24+
return a.createdAt - b.createdAt;
25+
});
26+
this.setState({
27+
list: [...sortedList]
28+
})
29+
}
30+
31+
sortByLatest() {
32+
const sortedList = this.state.list.sort((a, b) => {
33+
return b.createdAt - a.createdAt;
34+
});
35+
this.setState({
36+
list: [...sortedList]
37+
})
38+
}
39+
40+
addToEnd() {
41+
const date = new Date();
42+
const nextId = this.state.todoCounter + 1;
43+
const newList = [
44+
...this.state.list,
45+
{ id: nextId, createdAt: date }
46+
];
47+
this.setState({
48+
list: newList,
49+
todoCounter: nextId
50+
});
51+
}
52+
53+
addToStart() {
54+
const date = new Date();
55+
const nextId = this.state.todoCounter + 1;
56+
const newList = [
57+
{ id: nextId, createdAt: date },
58+
...this.state.list
59+
];
60+
this.setState({
61+
list: newList,
62+
todoCounter: nextId
63+
});
64+
}
65+
66+
render() {
67+
return(
68+
<div>
69+
<code>key=index</code><br/>
70+
<button onClick={this.addToStart.bind(this)}>
71+
Add New to Start
72+
</button>
73+
<button onClick={this.addToEnd.bind(this)}>
74+
Add New to End
75+
</button>
76+
<button onClick={this.sortByEarliest.bind(this)}>
77+
Sort by Earliest
78+
</button>
79+
<button onClick={this.sortByLatest.bind(this)}>
80+
Sort by Latest
81+
</button>
82+
<table>
83+
<tr>
84+
<th>ID</th><th></th><th>created at</th>
85+
</tr>
86+
{
87+
this.state.list.map((todo, index) => (
88+
<ToDo
89+
key={index}
90+
{...todo}
91+
/>
92+
))
93+
}
94+
</table>
95+
</div>
96+
)
97+
}
98+
}
99+
100+
ReactDOM.render(
101+
<ToDoList />,
102+
document.getElementById('root')
103+
);
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
const ToDo = (props) => (
2+
<tr>
3+
<td><label>{props.id}</label></td>
4+
<td><input/></td>
5+
<td><label>{props.createdAt.toTimeString()}</label></td>
6+
</tr>
7+
);
8+
9+
class ToDoList extends React.Component {
10+
constructor() {
11+
super();
12+
const date = new Date();
13+
const toDoCounter = 1;
14+
this.state = {
15+
list: [
16+
{ id: toDoCounter, createdAt: date },
17+
],
18+
toDoCounter: toDoCounter
19+
}
20+
}
21+
22+
sortByEarliest() {
23+
const sortedList = this.state.list.sort((a, b) => {
24+
return a.createdAt - b.createdAt;
25+
});
26+
this.setState({
27+
list: [...sortedList]
28+
})
29+
}
30+
31+
sortByLatest() {
32+
const sortedList = this.state.list.sort((a, b) => {
33+
return b.createdAt - a.createdAt;
34+
});
35+
this.setState({
36+
list: [...sortedList]
37+
})
38+
}
39+
40+
addToEnd() {
41+
const date = new Date();
42+
const nextId = this.state.toDoCounter + 1;
43+
const newList = [
44+
...this.state.list,
45+
{ id: nextId, createdAt: date }
46+
];
47+
this.setState({
48+
list: newList,
49+
toDoCounter: nextId
50+
});
51+
}
52+
53+
addToStart() {
54+
const date = new Date();
55+
const nextId = this.state.toDoCounter + 1;
56+
const newList = [
57+
{ id: nextId, createdAt: date },
58+
...this.state.list
59+
];
60+
this.setState({
61+
list: newList,
62+
toDoCounter: nextId
63+
});
64+
}
65+
66+
render() {
67+
return(
68+
<div>
69+
<code>key=id</code><br/>
70+
<button onClick={this.addToStart.bind(this)}>
71+
Add New to Start
72+
</button>
73+
<button onClick={this.addToEnd.bind(this)}>
74+
Add New to End
75+
</button>
76+
<button onClick={this.sortByEarliest.bind(this)}>
77+
Sort by Earliest
78+
</button>
79+
<button onClick={this.sortByLatest.bind(this)}>
80+
Sort by Latest
81+
</button>
82+
<table>
83+
<tr>
84+
<th>ID</th><th></th><th>created at</th>
85+
</tr>
86+
{
87+
this.state.list.map((todo, index) => (
88+
<ToDo
89+
key={todo.id}
90+
{...todo}
91+
/>
92+
))
93+
}
94+
</table>
95+
</div>
96+
)
97+
}
98+
}
99+
100+
ReactDOM.render(
101+
<ToDoList />,
102+
document.getElementById('root')
103+
);

0 commit comments

Comments
 (0)