[英]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.