[英]React Warning: Each child in a list should have a unique "key" prop when key is provided and unique
[英]React list element disappears in grandchild component when grandparent state is updated. Warning: Each child in a list should have a unique "key"
我創建了一個屬於側邊欄的功能組件。 它包含 3 個組件。
ProductFilters - main list component, fetches possible data filters from the server, provides a filters state which can be updated by child components when a filter is selected.
FilterOptions - 過濾器類別
選項- 代表過濾器菜單中的每個選項。 當被選中時,它會調用ProductFilters回調來更新過濾器列表。 選擇它后, filters
映射正在更新,並且...所選的Option
元素消失。 選擇空的地方后,react throws 和 error
index.js:1 警告:列表中的每個子項都應該有一個唯一的“鍵”屬性。 檢查
FilterOptions
的渲染方法
每個Option
元素都有它自己的唯一鍵,即選項名稱。 可能是什么問題?
這是我的代碼:
import axios from "axios";
import List from "@mui/material/List";
import ListItemButton from "@mui/material/ListItemButton";
import ListItemIcon from "@mui/material/ListItemIcon";
import ListItemText from "@mui/material/ListItemText";
import Collapse from "@mui/material/Collapse";
import InboxIcon from "@mui/icons-material/MoveToInbox";
import ExpandLess from "@mui/icons-material/ExpandLess";
import ExpandMore from "@mui/icons-material/ExpandMore";
import Button from "@mui/material/Button";
const Option = (props) => {
const [selected, setSelected] = useState(false);
const handleClick = () => {
setSelected(!selected);
props.setFilter(props.category, props.name, !selected);
};
return (
<ListItemButton
selected={selected}
sx={{ pl: 8 }}
onClick={handleClick}
>
<ListItemText primary={props.name} />
</ListItemButton>
);
};
const FilterOptions = (props) => {
const [open, setOpen] = useState(false);
const handleClick = () => {
setOpen(!open);
};
const displayOptions = () => {
const options = [];
for (const [key, option] of props.filter) {
options.push(
<Option
key={key}
name={option.name}
category={props.name}
setFilter={props.setFilter}
/>
);
}
return options;
};
return (
<Fragment>
<ListItemButton sx={{ pl: 4, fontSize: 12 }} onClick={handleClick}>
<ListItemText primary={props.name} />
</ListItemButton>
<Collapse in={open} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
{displayOptions()}
</List>
</Collapse>
</Fragment>
);
};
export default function ProductFilters(props) {
const [open, setOpen] = useState(false);
const [filters, setFilters] = useState(new Map());
const setFilter = (category, filter, selected) => {
const options = filters.get(category).set(filter, selected);
setFilters(new Map(filters.set(category, options)));
};
useEffect(() => {
const fetchFilters = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/api/product/filters`
);
const outputFilters = new Map();
res.data.map((filter) => {
const options = new Map();
filter.taxonomydata_set.map((option) => {
options.set(option.name, {
name: option.name,
selected: false,
});
});
outputFilters.set(filter.category, options);
});
setFilters(outputFilters);
} catch (err) {}
};
fetchFilters();
}, []);
const handleClick = () => {
setOpen(!open);
};
const displayFilters = () => {
let filterList = [];
for (const [categoryName, filterCat] of filters) {
filterList.push(
<FilterOptions
key={categoryName}
name={categoryName}
filter={filterCat}
setFilter={setFilter}
/>
);
}
return filterList;
};
const handleApplyFilters = () => {
console.log(filters);
};
return (
<List
sx={{
width: "100%",
maxWidth: 260,
bgcolor: "background.paper",
}}
component="nav"
aria-labelledby="nested-list-subheader"
>
<ListItemButton onClick={handleClick}>
<ListItemIcon>
<InboxIcon />
</ListItemIcon>
<ListItemText primary={props.ListTitle} />
{open ? <ExpandLess /> : <ExpandMore />}
</ListItemButton>
<Collapse in={open} timeout="auto" unmountOnExit>
<List>{displayFilters()}</List>
</Collapse>
<Button variant="contained" onClick={handleApplyFilters}>
Apply filters
</Button>
</List>
);
}
我認為您應該將“密鑰”應用於 Fragment
const FilterOptions = (props) => {
....
return (
<Fragment key={props.name}>
...
</Fragment>
);
}
問題解決了。 問題不在於鍵,它們設置正確。 問題出在處理程序函數中。 我已將地圖元素類型從 JSON 覆蓋為布爾值( selected ),這導致我的Option
組件在重新渲染期間不再使用 props.name 鍵控,因為名稱已被刪除並被布爾變量替換。
從:
const setFilter = (category, filter, selected) => {
const options = filters.get(category).set(filter, selected);
setFilters(new Map(filters.set(category, options)));
};
變成
const setFilter = (category, filter, selected) => {
const option = filters.get(category).get(filter);
option.selected = selected;
const options = filters.get(category).set(filter, option);
setFilters(new Map(filters.set(category, options)));
};
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.