传递给子组件时道具未定义(反应钩子)
Posted
技术标签:
【中文标题】传递给子组件时道具未定义(反应钩子)【英文标题】:Props is undefined when passed to a child component (react hooks) 【发布时间】:2021-11-18 19:03:43 【问题描述】:我正在构建一个简单的议程组件,但遇到了问题。这个想法是,当一个人点击这一天,然后看到这一天的培训。我的逻辑如下
-
点击按钮时,我将状态设置为日期 ID
在现有活动项上三元运算符呈现组件
我将函数调用作为道具传递,它返回最新的对象。
我尝试将函数调用放到 handleClick 函数中,但没有帮助。对我来说,似乎函数没有及时返回值让组件传递它,但我不知道如何绕过这个问题。 这是包含所有内容的代码框 - 请帮助
https://codesandbox.io/s/cranky-johnson-s2dj3?file=/src/scheduledTrainingCard.js
这是父组件的代码,问题就在这里
import React, useState from "react";
import Transition, Grid, Button, Container from "semantic-ui-react";
import ScheduledTrainingCard from "./scheduledTrainingCard";
function ScheduleComponent(props)
const days = [
id: "1",
dayTrainings: [
time: "20:15:00",
training: "zumba",
trainer: "joe"
,
time: "16:00:00",
training: "stretching",
trainer: "lily"
],
date:
"Thu Dec 28 1995 00:00:00 GMT+0100 (Central European Standard Time)",
createdAt: "2021-07-14T19:30:59.177Z"
,
id: "2",
dayTrainings: [
time: "23:15:00",
training: "boxing",
trainer: "phoebe"
,
time: "15:00:00",
training: "dancing",
trainer: "kate"
],
date: "Thu Sep 23 2021 20:57:38 GMT+0200 (Central European Summer Time)",
createdAt: "2021-09-23T19:01:53.801Z"
,
id: "3",
dayTrainings: [
time: "23:15:00",
training: "ballet",
trainer: "nataly"
,
time: "12:00:00",
training: "crossfit",
trainer: "sheldon"
],
date: "Fri Jul 23 2021 21:02:37 GMT+0200 (Central European Summer Time)",
createdAt: "2021-09-23T19:03:31.161Z"
];
const [activeItem, setActiveItem] = useState("");
const handleItemClick = (e) =>
setActiveItem(e.target.name);
;
function showSelectedDay(arr, dayId)
arr.forEach((element, index) =>
if (dayId === element.id)
console.log("selected day is " + element.date);
let trainings = element.dayTrainings;
trainings.map((training) =>
return training;
);
else
console.log("not selected, day id is " + element.id);
);
const ScheduleComponent = (
<Container style= textAlign: "left" >
<h1 style= textAlign: "center" >Training Schedule</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Incidunt
dolor unde repudiandae culpa ullam, asperiores officiis ratione
repellat quaerat nihil vel corporis distinctio vero doloribus dolore
optio commodi voluptatum inventore.
</p>
<Container>
<Grid style= margin: "2rem auto", textAlign: "center" relaxed>
<Button onClick=(e) => handleItemClick(e) name="1">
Monday
</Button>
<Button onClick=(e) => handleItemClick(e) name="2">
Tuesday
</Button>
<Button onClick=(e) => handleItemClick(e) name="3">
Wednesday
</Button>
</Grid>
</Container>
<Container>
activeItem && (
<ScheduledTrainingCard
dayTraining=showSelectedDay(days, activeItem)
></ScheduledTrainingCard>
)
</Container>
</Container>
);
return ScheduleComponent;
export default ScheduleComponent;
【问题讨论】:
你 showSelectedDay 函数没有返回任何东西......你从 forEach 循环返回 【参考方案1】:首先为selectedDays
定义一个新状态:
const [activeItem, setActiveItem] = useState("");
const [selectedDays, setSelectedDays] = useState([]);
然后根据用户的选择设置setSelectedDays
的值和activeItem
:
useEffect(() =>
let filteredDays = days.filter((x) => x.id === activeItem);
setSelectedDays(filteredDays);
, [activeItem]);
最后定义一个新函数来渲染这些日子。因为days是一个层次数组,所以需要循环两次:
const showDays = () =>
return selectedDays.map((days, index) =>
return days.dayTrainings.map((item, i) =>
let dayTraining =
id: days.id,
time: item.time,
trainer: item.trainer,
training: item.training
;
return (
<ScheduledTrainingCard
dayTrainings=dayTraining
></ScheduledTrainingCard>
);
);
);
;
const ScheduleComponent = (
<Transition.Group>
<Container style= textAlign: "left" >
<h1 style= textAlign: "center" >Training Schedule</h1>
<p>
Lorem ipsum dolor sit amet consectetur adipisicing elit. Incidunt
dolor unde repudiandae culpa ullam, asperiores officiis ratione
repellat quaerat nihil vel corporis distinctio vero doloribus dolore
optio commodi voluptatum inventore.
</p>
<Container>
<Grid style= margin: "2rem auto", textAlign: "center" relaxed>
<Button onClick=(e) => handleItemClick(e) name=1>
Monday
</Button>
<Button onClick=(e) => handleItemClick(e) name=2>
Tuesday
</Button>
<Button onClick=(e) => handleItemClick(e) name=3>
Wednesday
</Button>
</Grid>
</Container>
<Container>activeItem && selectedDays && showDays()</Container>
</Container>
</Transition.Group>
);
return ScheduleComponent;
【讨论】:
感谢您对它的改进,使用 useEffect 很不错,我真的很喜欢。我知道如果我们将状态作为一个数组,我可以访问它的内容直到状态改变,对吗? @BadgerWannaBe 绝对是的!当状态发生变化时,您可以通过整个组件中的新状态访问它,而无需将其值作为参数发送给组件内的另一个函数。 @BadgerWannaBe 如果回答成功,您可以接受它以获取更多资源。 嗨 Majid,我正在测试你的答案我遇到了另一个问题 - 我的实际应用程序正在使用 Apolli useQuery hook 来获取数据,在我看来 useEffect 没有看到或得到“days”数组及时。这里看起来完全是const [activeItem, setActiveItem] = useState(""); const [selectedDays, setSelectedDays] = useState([]); const loading, data: getDays: days = = useQuery(FETCH_DAYS_QUERY); useEffect(() => let filteredDays = days.filter((x) => x.id === activeItem); console.log(filteredDays); setSelectedDays(filteredDays); , [activeItem]);
我之前没试过useQuery
!但是如果你的意思是调用一个api,你只需要在页面加载成功时调用新的api,useEffect(( )=> ,[ ])
并获取天数,最后定义一个新的状态并使用api结果设置状态。所以你可以使用新状态而不是静态 arr。【参考方案2】:
问题是您在地图内使用返回。 看看我是怎么做到的:
1- 我们不需要函数showSelectedDay
,所以我将其删除。
2- 我们不需要状态const [activeItem, setActiveItem] = useState("");
。
3- 添加新状态const [dayTrainings, setDayTrainings] = useState([]);
4- 将handleItemClick
更新为:
const [dayTrainings, setDayTrainings] = useState([]);
const handleItemClick = (e) =>
days.forEach((element, index) =>
if (e.target.name === element.id)
console.log("selected day is " + element.date);
setDayTrainings(element.dayTrainings);
else
console.log("not selected, day id is " + element.id);
);
;
5- 在渲染返回中:
dayTrainings.length > 0 && (
<ScheduledTrainingCard
dayTraining=dayTrainings
></ScheduledTrainingCard>
)
ScheduledTrainingCard
的示例:
export default function scheduledTrainingCard(props)
console.log(props.dayTraining);
return (<>
props.dayTraining.map((item, index) =>
<p key=index>
item['time']<br/>
item['training']<br/>
item['trainer']<br/>
<br/><br/>
</p>)
</>);
输出示例: output
【讨论】:
感谢您在将数组保存到状态时的彻底解释和改进。我对渲染有疑问 - 所以在这个解决方案中,当我们有超过 0 次培训时,它会被渲染,我找不到任何缺陷,但仍然没有很多人使用它(在教程和其他示例中)。真的不明白为什么不。【参考方案3】:你可以这样做
const handleItemClick = (e) =>
days.map(item =>
if(item.id === e.target.name)
setActiveItem(item)
)
;
并改变这一行
activeItem &&
activeItem.dayTrainings.map(day => <ScheduledTrainingCard dayTraining=day/>)
【讨论】:
以上是关于传递给子组件时道具未定义(反应钩子)的主要内容,如果未能解决你的问题,请参考以下文章