簡體   English   中英

反應子組件 state 未定義,但可以使用 console.log 看到 state

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

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM