key là cách bạn nói cho React biết phần tử nào trong danh sách là phần tử nào giữa hai lần render. Không có nó, React chỉ còn vị trí trong mảng để so — và vị trí thì thay đổi mỗi khi bạn chèn, xoá hay sắp xếp lại.
Hình dung một hàng ghế đánh số. Nếu ghế có tên người, thêm một người vào đầu hàng thì ai vẫn ngồi ghế của người đó. Nếu chỉ có số thứ tự, thêm một người vào đầu là toàn bộ hàng bị đánh số lại — React tưởng mọi phần tử đều đổi nội dung.
// Sai: index làm key
{todos.map((todo, i) => <TodoItem key={i} todo={todo} />)}
// Đúng: id ổn định từ dữ liệu
{todos.map((todo) => <TodoItem key={todo.id} todo={todo} />)}Hậu quả của bản sai không phải chỉ là chậm. Khi key là index và bạn xoá phần tử đầu, React thấy phần tử ở index 0 vẫn tồn tại nên giữ nguyên DOM node và state của nó, chỉ đổi props. Kết quả là: chữ đã gõ trong ô input nhảy sang dòng khác, checkbox tick sai dòng, animation chạy nhầm phần tử. Đây là loại bug rất khó lần ra vì code trông hoàn toàn hợp lý.
Vài ràng buộc cần nhớ: key chỉ cần duy nhất giữa các phần tử cùng cấp (sibling), không cần duy nhất toàn ứng dụng. Nó không phải prop — component con không đọc được props.key; muốn dùng id thì truyền thêm một prop riêng.
Lưu ý: Dùng index làm key chỉ an toàn khi danh sách tĩnh, không sắp xếp lại và không có state bên trong mỗi dòng. Đừng dùng Math.random() — key đổi mỗi lần render khiến React huỷ và dựng lại toàn bộ danh sách.