React列表key警告问题:已设置唯一标识仍报错
React列表渲染key报错问题解决
问题场景
学习React时,使用map渲染国家列表,已为列表元素添加唯一key,但控制台仍报错:
Warning: Each child in a list should have a unique "key" prop.
报错指向CountryList组件。尝试给按钮添加相同或独立key后,问题依旧。
相关代码如下:
列表渲染代码
return ( countries.map(country => { return <> <div key={country.name.common}> {country.name.common} <button onClick={() => setCountries([country])}>show</button> </div> </> }) )
数据获取代码
useEffect(() => { axios.get("https://restcountries.com/v3.1/all") .then(response => setCountries(response.data)) }, [])
过滤逻辑代码
const handleFilterChange = (event) => { setFilter(event.target.value) const filtered = countries.filter(country => country.name.common.toLowerCase().includes(event.target.value)) setCountries(filtered) }
问题原因
你把key加在了内部的div上,但map返回的最外层元素是React Fragment(<>)。React会将Fragment视为列表的直接子元素,因此只会检查Fragment的key,而忽略内部元素的key,导致key缺失报错。
解决方法
有两种可行方案:
方案1:移除不必要的Fragment
因为你的Fragment内部只有一个div,完全可以直接返回div,把key保留在div上:
return ( countries.map(country => { return <div key={country.name.common}> {country.name.common} <button onClick={() => setCountries([country])}>show</button> </div> }) )
方案2:给Fragment添加key
如果确实需要保留Fragment(比如后续要添加多个同级元素),需将key移到Fragment上(注意要使用完整的<React.Fragment>语法,短语法<>不支持key属性):
return ( countries.map(country => { return <React.Fragment key={country.name.common}> <div> {country.name.common} <button onClick={() => setCountries([country])}>show</button> </div> </React.Fragment> }) )
额外提示
- 建议使用国家数据中的
cca3字段作为key,它是每个国家的唯一三位代码,比name.common更稳定(避免出现重名国家的极端情况)。 - 过滤逻辑中直接修改原
countries数组可能导致数据丢失,建议保留原始数据,通过filter结合filter状态来渲染列表,不要直接覆盖原数据:
// 初始化时保存原始数据 const [allCountries, setAllCountries] = useState([]) const [filteredCountries, setFilteredCountries] = useState([]) const [filter, setFilter] = useState('') useEffect(() => { axios.get("https://restcountries.com/v3.1/all") .then(response => { setAllCountries(response.data) setFilteredCountries(response.data) }) }, []) const handleFilterChange = (event) => { const value = event.target.value.toLowerCase() setFilter(value) const filtered = allCountries.filter(country => country.name.common.toLowerCase().includes(value)) setFilteredCountries(filtered) } // 渲染时使用filteredCountries return ( filteredCountries.map(country => { return <div key={country.cca3}> {country.name.common} <button onClick={() => setFilteredCountries([country])}>show</button> </div> }) )
内容的提问来源于stack exchange,提问作者shanehowe
相关产品推荐
相关产品推荐

