[英]React child components state is undefined but can see state using console.log
我有一个父组件,它使用 fetch 从 API 端点获取数据。 此数据应按原样显示。 父组件将对象数组的元素传递给子组件。 在子组件中,当我执行控制台日志时,我可以看到 state 未定义且设置了 state 时。 我遇到的问题是,当我尝试访问 state 的密钥(即 ticket.title)时,我收到一条错误消息,提示该票证未定义。 任何帮助都会很棒。
票务清单
import React, { useEffect, useState } from 'react';
import styled from 'styled-components';
import TicketDetails from "./TicketDetails"
export default function TicketList() {
const [tickets, updateTickets] = useState([])
const [ticketIndex, updateticketIndex] = useState("0")
useEffect(() => {
async function fetchTickets() {
const response = await fetch("/api/v1/tickets")
const json = await response.json()
updateTickets(json.data)
}
fetchTickets()
}, [])
return (
<Wrapper>
< div >
<TableTitle>
<h3>Tickets</h3>
<button type="submit">Create A Ticket</button>
</TableTitle>
{
tickets.map((ticket, index) => (
<ListInfo key={ticket._id} onClick={() => updateticketIndex(index)}>
<Left>
<p>{ticket.project}</p>
<p>{ticket.title}</p>
<p>{ticket.description}</p>
</Left>
<Right>
<p>{ticket.ticketType}</p>
<p>{ticket.ticketStatus}</p>
<p>{ticket.ticketPriority}</p>
</Right>
</ListInfo>
))
}
</div>
<TicketDetails key={tickets._id} data={tickets[ticketIndex]} />
</Wrapper>
);
}
const Wrapper = styled.div`
display: flex;
background: white;
grid-area: ticketarea;
height: calc(100vh - 4.25rem);
`
const ListInfo = styled.div`
display: flex;
justify-content: space-between;
width: 100%;
padding: .5rem .75rem;
border-bottom: solid 1px #ccc;
`;
const Left = styled.div`
display: flex;
flex: 2;
flex-direction: column;
p {
padding: .25rem;
}
`;
const Right = styled.div`
display: flex;
flex: 1;
flex-direction: column;
align-items: end;
width: 500px;
p {
padding: .25rem;
}
`;
const TableTitle = styled.div`
display: flex;
justify-content: space-between;
padding: 1rem 1rem;
border-bottom: solid 1px #ccc;
button {
padding: .5rem;
}
`;
票务详情
import React, { useEffect, useState } from 'react'
// import TicketInfo from './TicketInfo'
import TicketNotes from "./TicketNotes"
import styled from "styled-components"
export default function TicketDetail(data) {
const [ticket, setTicket] = useState(data)
useEffect(() => {
setTicket(data)
}, [data])
console.log(ticket.data)
return (
<Main>
<TicketInfo key={ticket._id}>
<h2>{ticket.title}</h2>
<Info>
<div>
<InfoItem>
<p>Project</p>
<p>{ticket.project}</p>
</InfoItem>
<InfoItem>
<p>Assigned Dev</p>
<p>{ticket.assignedDev}</p>
</InfoItem>
<InfoItem>
<p>Created By</p>
<p>{ticket.submitter}</p>
</InfoItem>
</div>
<div>
<InfoItem>
<p>Type</p>
<p>{ticket.ticketType}</p>
</InfoItem>
<InfoItem>
<p>Status</p>
<p>{ticket.ticketStatus}</p>
</InfoItem>
<InfoItem>
<p>Priority</p>
<p>{ticket.ticketPriority}</p>
</InfoItem>
</div>
</Info>
<Description>{ticket.description}</Description>
</TicketInfo>
<TicketNotes />
<TicketComment>
<textarea name="" id="" cols="30" rows="10" />
<button type="submit">Submit</button>
</TicketComment>
</Main>
)
}
const TicketInfo = styled.div`
margin: .5rem;
h2{
padding: 0.5rem 0;
}
`;
const Description = styled.p`
padding-top: .5rem;
`;
const Info = styled.div`
display: flex;
justify-content: space-between;
border-bottom: solid 1px #ddd;
`;
const InfoItem = styled.section`
margin: .5rem 0;
p:nth-child(1) {
text-transform: uppercase;
color: #ABB1B6;
font-weight: 500;
padding-bottom: .25rem;
}
`;
const Main = styled.div`
background: white;
`
const TicketComment = styled.div`
display: flex;
flex-direction: column;
width: 40rem;
margin: 0 auto ;
input[type=text] {
height: 5rem;
border: solid 1px black;
}
textarea {
border: solid 1px black;
}
button {
margin-top: .5rem;
padding: .5rem;
width: 6rem;
}
`;
这里有几个问题,让我们按顺序解决。
票证未定义
挂载TicketList
时,它会获取票证。 当它渲染时,它会立即渲染TicketDetail
。 票证获取请求不会完成,因此tickets
是未定义的。 这就是TicketDetail
出错的原因。 解决方案是在票可用之前阻止呈现TicketDetail
。 你有几个选择。
一个简单的方法是在数据可用之前阻止渲染:
{ !!tickets.length && <TicketDetails key={tickets._id} data={tickets[ticketIndex]} />
这使用了逻辑运算符在 JS 中的工作方式。 在 JS falsey && expression
返回falsey
,而true && expression
返回expression
。 在这种情况下,我们将ticket.length
转换为 boolean。 如果它为 0(即未加载,因此为 false),我们返回 false,React 简单地将其丢弃。 如果它大于 0(即已加载,因此为真),我们渲染组件。
但这并不能真正带来积极的用户体验。 理想情况下,这可以通过显示某种加载微调器或类似的东西来解决:
{
!!tickets.length
? <TicketDetails . . . />
: <LoadingSpinner />
}
子数据访问
在 TicketDetail 中,您似乎打算解构数据。 目前,您正在使用整个道具 object 并将其设置为ticket
。 解决这个问题应该可以解决问题的另一半。
范式
你没有特别要求这个,但我想备份并问你为什么将这个道具放入state? 通常,这仅在执行某种临时编辑时完成,例如预填充表单以进行编辑。 在您的情况下,您似乎只想呈现票证详细信息。 这是一种反模式,将其放入 state 只会添加更多代码,对您没有任何帮助。 React 中的约定是直接渲染道具,不需要 state。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.