每個React的初學者,在調試程序時,都會遇到這樣的警告:Warning: Each child in a list should have a unique "key" prop. 如下面的代碼:
const list = ['Learn React', 'Learn GraphQL'];const ListWithoutKey = () => (<div><ul>{list.map((item) => (<li>{item}</li>))}</ul></div>
);
這個警告提示我們,需要為列表中的每個元素添加 key 屬性。如下面的代碼:
const ListWithoutKey = () => (<div><ul>{list.map((item, index) => (<li key={index}>{item}</li>))}</ul></div>
);
使用上面的代碼調試時,之前的警告會消失,但其實在其背后,有一個隱式的 bug。當你對列表進行重新排序時,特別是當你添加了非受控的元素,問題就會發生。
如果你的代碼如下:
const initialList = ['Learn React', 'Learn GraphQL'];const ListWithUnstableIndex = () => {const [list, setList] = React.useState(initialList);const handleClick = event => {setList(list.slice().reverse());};return (<div><ul>{list.map((item, index) => (<li key={index}><label>{item}</label></li>))}</ul><button type="button" onClick={handleClick}>Reverse List</button></div>);
};
運行你的代碼,點擊按鈕對列表進行重新排序,看樣子,一切正常。
可是當你添加了不受控的元素時,假如你的代碼如下:
const initialList = ['Learn React', 'Learn GraphQL'];const ListWithUnstableIndex = () => {const [list, setList] = React.useState(initialList);const handleClick = event => {setList(list.slice().reverse());};return (<div><ul>{list.map((item, index) => (<li key={index}><label><input type="checkbox" />{item}</label></li>))}</ul><button type="button" onClick={handleClick}>Reverse List</button></div>);
};
在上述的代碼中,checkbox 是非受控元素,當你運行上述的代碼時,運行的結果,可能和你相像的不太一致。
// 列表最初的樣子[x] Learn React
[ ] Learn GraphQL// 點擊按鈕,列表重新排序后的樣子[x] Learn GraphQL
[ ] Learn React
這種結果顯然不是你想要的,那這背后終究發生了什么呢?
// 列表當初的樣子[x] Learn React (index = 1)
[ ] Learn GraphQL (index = 2)// 點擊按鈕,列表重新排序后的樣子[x] Learn GraphQL (index = 1)
[ ] Learn React (index = 2)
那如何解決這個問題呢,辦法當然有,這次,我們使用了相當穩定的元素作為 key 屬性。代碼如下:
const initialList = [{ id: 'a', name: 'Learn React' },{ id: 'b', name: 'Learn GraphQL' },
];const ListWithStableIndex = () => {const [list, setList] = React.useState(initialList);const handleClick = event => {setList(list.slice().reverse());};return (<div><ul>{list.map(item => (<li key={item.id}><label><input type="checkbox" />{item.name}</label></li>))}</ul><button type="button" onClick={handleClick}>Reverse List</button></div>);
};
點擊按鈕,列表重新排序后,背后發生了變化。
// 列表最初的樣子
[x] Learn React (id = a)
[ ] Learn GraphQL (id = b)// 點擊按鈕,列表重新排序后的樣子[ ] Learn GraphQL (id = b)
[x] Learn React (id = a)
在這里,我們使用了 id 作為 key 屬性,當然,你也可以使用列表中的其他元素,但前提是這個元素是不可改變的唯一值。
不管怎樣,仍然值得注意的是,只要你的列表保持的順序或大小沒有改變,使用索引是可以的。然后,列表中每個項目的位置不會改變——它與索引一樣穩定——因此使用索引是可以的。
原文鏈接:Why do we need a React List Key