繁体   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