将对象的数组属性作为 React 组件 prop 传递会引发异常
我试图理解为什么我不能将数据对象的数组属性作为 prop 传递到组件中。认为这是一个关于 React 工作原理的基本理解问题,和/或在这种情况下的陷​​阱……任何见解都值得赞赏!
上下文:我正在为 React 中的会议制作一个展示页面。此展示页面将显示“title”、“description”等元素,并遍历“agenda_items”列表。
数据来自单个 JSON API 响应。“agenda_items”是数据结构中的嵌套数组。
{
data: {
id: 2,
title: "Example title",
description: "Example description",
agenda_items: [
{
id: 5,
title: "Topic 1"
},
{
id: 6,
title: "Topic 2"
}
]
}
}
以下实现有效。我正在使用
React.useState()
分别设置
meeting
和
agenda_items
,尽管
agenda_items
理论上可以通过
meeting.agenda_items
访问。
const Meeting = () => {
const [meeting, setMeeting] = React.useState([]);
const [agenda_items, setAgendaItems] = React.useState([]);
const handleFetchMeeting = React.useCallback(() => {
axios
.get(url)
.then(result => {
setMeeting(result.data);
setAgendaItems(result.data.agenda_items);
})
});
React.useEffect(() => {
handleFetchMeeting();
}, []);
return (
<div>
<h1>{meeting.title}</h1>
<AgendaList list={agenda_items} />
</div>
);
}
const AgendaList = ({ list }) => {
return (
<div>
<h3>Agenda</h3>
{list.map(item => (
<Item
key={item.id}
item={item}
/>
))}
</div>
);
}
但是,如果我尝试将
meeting.agenda_items
作为参数传递到
<AgendaList>
,它会引发异常。我原本以为这两种实现是等效的,但似乎不是?
...
return (
<div>
<h1>{meeting.title}</h1>
<AgendaList list={meeting.agenda_items} />
</div>
);
)
//INSTEAD OF
/*
return (
<div>
<h1>{meeting.title}</h1>
<AgendaList list={agenda_items} />
</div>
);
)
*/
Uncaught TypeError: Cannot read property 'map' of undefined
at AgendaList (Meeting.jsx:52)
at renderWithHooks (react-dom.development.js:14972)
at mountIndeterminateComponent (react-dom.development.js:17734)
at beginWork (react-dom.development.js:18935)
at HTMLUnknownElement.callCallback (react-dom.development.js:3922)
at Object.invokeGuardedCallbackDev (react-dom.development.js:3971)
at invokeGuardedCallback (react-dom.development.js:4031)
at beginWork$1 (react-dom.development.js:23780)
at performUnitOfWork (react-dom.development.js:22616)
at workLoopSync (react-dom.development.js:22553)
为什么 React 在查找/渲染
{meeting.title} 时没有问题,但随后却调用
{meeting.agenda_items} 未定义?
这个错误是否发生在组件第一次渲染时,在异步数据调用完成之前?
将
const AgendaList = ({ list }) => {
return (
<div>
<h3>Agenda</h3>
{list.map(item => (
<Item
key={item.id}
item={item}
/>
))}
</div>
);
}
更改为:
const AgendaList = ({ list }) => {
return (
<div>
<h3>Agenda</h3>
{list?.map(item => (
<Item
key={item.id}
item={item}
/>
))}
</div>
);
}
// if your code has support for optional chaining
或:
const AgendaList = ({ list }) => {
return (
<div>
<h3>Agenda</h3>
{list.length ? list.map(item => (
<Item
key={item.id}
item={item}
/>
)) : <></>}
</div>
);
}
meeting.agenda_items
可能在呈现 <AgendaList ... /> 时不可用。因此,基本上发生的事情是,您正在映射当时可能不存在(在本例中为
undefined
)的数据。由于数据准备就绪后值就会更新,并且组件会获得更新,所以这个新选项告诉组件只有在
list
有长度时才通过它进行映射,因为在这种情况下您需要一个对象(数组)。
当
list
尚未准备好时,您可以进一步添加加载器作为另一个选项,或者处理
list
实际上也为空的情况。
首次渲染时,axios 请求尚未完成。此时,您已将默认值设置为数组。
{meeting.title} 将简单地评估为未定义,并在渲染中被忽略。
同样,
meeting.agenda_items
也将未定义,因此
list.map()
将等同于
undefined.map()
并将引发错误。
当您仅传递
agenda_items
时,它已在
useState()
中定义为空数组,并且 list.map() 将等同于
[].map()
,这是有效的