唯一 ID 无法修复在 React 中呈现嵌套列表时"unique key"错误



我无法摆脱经典的React"列表中的每个子项都应该有一个唯一的关键字">。我正在渲染一个大数组,其中的项可以包含子项。

为了防止所有这些,我为每个项目创建了一个具有唯一id的数据结构。

这是我的数据:

export const assetListConfig: RolesListItem[] = [
{
id: 1,
title: t('Asset creation'),
name: 'Asset-Create',
type: 'switch',
},
{
id: 2,
title: t('Edit asset info'),
name: 'Asset-Edit',
type: 'switch',
},
{
id: 3,
title: t('Archive'),
name: 'Asset-Archive',
type: 'switch',
},
{
id: 4,
title: t('Delete'),
name: 'Asset-Delete',
type: 'switch',
subLists: [
{
subListWatch: 'Asset-Delete',
items: [
{
id: 5,
title: t('Bulk deletion'),
name: 'Asset-Delete-Bulk',
type: 'switch',
},
],
},
],
},
{
id: 6,
title: t('Resources'),
name: 'Asset-Manage-Resources',
type: 'switch',
},
{
id: 7,
title: t('Enable public'),
name: 'Asset-Set-Public',
type: 'switch',
},
{
id: 8,
title: t('Enable redirect'),
name: 'Asset-Set-Redirect',
type: 'switch',
},
{
id: 9,
title: t('Enable tickets'),
name: 'Asset-Enable-Tickets',
type: 'switch',
},
{
id: 10,
title: t('Edit hierarchy'),
name: 'Asset-Edit-Hierarchy',
type: 'switch',
itemWatch: ['Asset-Edit'],
},
{
id: 11,
title: t('Locations'),
name: 'Asset-Location',
type: 'switch',
},
{
id: 12,
title: t('Manage asset tags'),
name: 'Asset-Manage-Tags',
type: 'switch',
},
{
id: 13,
title: t('Logbook'),
name: 'Asset-Logbook-Read',
type: 'switch',
subLists: [
{
subListWatch: 'Asset-Logbook-Read',
items: [
{
id: 14,
title: t('Comment'),
name: 'Asset-Logbook-Comment',
type: 'switch',
},
{
id: 15,
title: t('Allow export'),
name: 'Asset-Logbook-Export',
type: 'switch',
},
],
},
],
},
{
id: 16,
title: t('Components'),
name: 'Component-Read',
type: 'switch',
subLists: [
{
subListWatch: 'Component-Read',
items: [
{
id: 17,
title: t('Instances'),
name: 'Component-Instance',
type: 'radio',
radioOptions: [
{ label: t('Manage'), value: 'Component-Instance-Manage' },
{
label: t('Delete'),
value: 'Component-Instance-Delete',
inputWatch: 'Component-Instance-Manage',
},
],
},
{
id: 18,
title: t('Models'),
name: 'Component-Model',
type: 'radio',
radioOptions: [
{
label: t('Manage'),
value: 'Component-Model-Manage',
inputWatch: 'Component-Instance-Manage',
},
{
label: t('Delete'),
value: 'Component-Model-Delete',
inputWatch: 'Component-Model-Manage',
},
],
},
],
},
],
},
{
id: 19,
title: t('Workshifts'),
name: 'Asset-Running-Read',
type: 'switch',
subLists: [
{
subListWatch: 'Asset-Running-Read',
items: [
{
id: 20,
title: t('Manage status'),
name: 'Asset-Running-Status-Manage',
type: 'switch',
},
{
id: 21,
title: t('Manage expectations'),
name: 'Asset-Running-Expectation-Manage',
type: 'switch',
},
{
id: 22,
title: t('Manage schedules'),
name: 'Asset-Running-Schedule-Manage',
type: 'switch',
},
],
},
],
},
];

我用.map渲染列表也用于无线电组选项和项目子列表。

这是我得到错误的组件:

import shortid from 'shortid'
export const UserRolesList: React.FC<ListItemProps> = ({
listConfig,
userData,
isSubList = false,
}) => {

handleChange  ecc ecc...

return (
<RolesListWrapper isSubList={isSubList}>
<ul
className="list--unbulleted display--ib full-width"
>

/* FIRST LIST RENDERING */
**{listConfig.map((listItem, index) => {
const {
name,
title,
type,
radioOptions = [],
selectOptions = [],
id: skillId,
subLists,
} = listItem;**
const visibleOptions = renderVisibleOptions(radioOptions);
return (
<>
{isListItemVisible(listItem) ? (
**<li
className={`pad pad-double--sides shadow--list-item ${
index !== listConfig.length - 1 ? 'push--bottom' : ''
}`}
key={skillId}
style={
isSubList
? {
padding: '0',
boxShadow: 'none',
}
: {
width: 'auto',
minWidth: '350px',
}
}
>**
<div className="full-width flex--space-items">
<div
className="pad flex--align-center"
style={{
paddingLeft: isSubList ? 'var(--base-space)' : '',
flexBasis: '160px',
}}
>
{title}
</div>
{type === 'switch' ? (
<div className="pad flex--align-center">
<Switch
onColor="#21b151"
offColor="#e02f2f"
checked={findActiveSkill(name)}
onChange={() => handleSkillChange(name)}
disabled={isAddingSkill || isRemovingSkill}
/>
</div>
) : null}
{type === 'radio' ? (
**<div
className="flex-item--fill"
style={{
display: 'grid',
gridTemplateColumns: 'repeat(3,1fr)',
}}
>
/* SECOND LIST RENDERING */
{visibleOptions.map((opt) => (
<div
className="flex--align-center"
style={{
gridColumn: opt.value.includes('Delete')
? '3'
: undefined,
}}
key={shortid.generate()}
>**
<input
type="checkbox"
className="qtrack-form-input__selection"
value={opt.value}
id={opt.value}
checked={findActiveSkill(opt.value)}
onChange={(e) =>
handleSkillChange(e.target.value)
}
disabled={isAddingSkill || isRemovingSkill}
/>
<label
style={{ margin: '5px 0' }}
htmlFor={opt.value}
>
{opt.label}
</label>
</div>
))}
</div>
) : null}
{type === 'select' ? (
<div style={{ margin: '0', minWidth: '220px' }}>
<SimpleSelect
selectOptions={selectOptions}
value={selectOptions.find((opt) =>
skills.includes(opt.value),
)}
isMulti={false}
isClearable
errors={undefined}
onChange={(e: string) => handleSelectChange(e, name)}
name="roles-select"
isDisabled={isAddingSkill || isRemovingSkill}
/>
</div>
) : null}
</div>
{subLists ? (
<SubListHandler subLists={subLists} userData={userData} />
) : null}
</li>
) : null}
</>
);
})}
</ul>
</RolesListWrapper>
);
};

这就是我渲染子列表的组件:

export const SubListHandler: React.FC<{
subLists: RolesList[];
userData: UserData;
}> = ({ subLists, userData }) => (
<>
/* THIRD AND LAST LIST RENDER */
{subLists.map((list) => {
const { subListWatch, items: subItems } = list;
const isSubListVisible = userData.skills.includes(subListWatch);
**const subListId = shortid.generate();**
return (
<div key={subListId}>
{isSubListVisible ? (
**<div>**
{list.title ? (
<div className="txt--bold pad--left push--top">
{list.title}
</div>
) : null}
<div className="push--ends pad--left">
<UserRolesList
listConfig={subItems}
userData={userData}
isSubList
/>
</div>
</div>
) : null}
</>
);
})}
</>
);

正如您所看到的,我正在为组件中的所有三个映射方法使用唯一的ID。当我在控制台中记录我使用的ID时,就会确认这一点。他们都不一样。

我不知道我做错了什么,或者我是否在扰乱条件渲染或嵌套组件

我试图在代码中突出显示列表呈现的时间。这对我来说似乎很尖锐,因为我为每个列表子项都有唯一的id,但它总是给我带来一个错误。

如果你发现我的代码有问题,请告诉我。非常感谢!

您需要在列表项的'key'属性中使用唯一的id。即

const todoItems = todos.map((todo) =>
<li key={todo.id}>
{todo.text}
</li>
);

最新更新