Redux Toolkit 查询未获取数据

2024-02-05

I am trying to fetch data with RTK Query in next.js project and everything were fine until I had to fetch some more data from /api/exams endpoint. I have fetched almost everything from that endpoint and i know that's working fine but i still can't fetch some data from it. I'll provide screenshots of all code that's related to it. ok so here is the code where endpoints are: enter image description here

Then let's continue with exams-response where i define body of endpoint: enter image description here

Now I will provide code in my custom hook where i import that data from api/exams endpoint query: enter image description here

现在我将显示我使用它们的实际页面的代码,以及我认为问题也可能出在我将在此之后提供的另一个文件中:

import { memo } from "react"
import { useIntl } from "react-intl"
import Stack from "@mui/material/Stack"
import Typography from "@mui/material/Typography"

import { ExamoTypesEnum } from "src/common/types/examo-types-enum"
import { rolesEnum } from "src/core/roles-enum"
import { useExamAssign } from "src/features/exams/hooks/use-exam-assign"
import { useExams } from "src/features/exams/hooks/use-exams"
import { useStartExam } from "src/features/exams/hooks/use-start-exam"
import { useIsMobile } from "src/helpers/use-is-mobile"
import { useAppSelector } from "src/redux/hooks"
import { ExamoCard } from "src/ui/examo/examo-card"
import { ExamoCardsGrid } from "src/ui/examo/examo-cards-grid"
import { ExamoHeader } from "src/ui/examo/examo-header"
import { CustomizedDialogs } from "src/ui/filter"
import { LoadingSpinner } from "src/ui/loading-spinner"
import { styled } from "src/ui/theme"
import { UnauthenticatedComponent } from "src/ui/unauthenticated"

import { useTags } from "../tags/hooks/use-tags"
import { useActiveExamQuery } from "./api"

const Ourbox = styled.div`
  display: flex;
  justify-content: space-between;
`

export const ExamsPage = memo(() => {
  const isMobile = useIsMobile()
  const userRole = useAppSelector((state) => state.auth.role)
  const intl = useIntl()

  const {
    exams,
    isLoadingExams,
    selectedTags,
    setSelectedTags,
    checkedFilterTags,
    setCheckedFilterTags,
  } = useExams()

  const { availableTags } = useTags()
  const isLoadingAnExam = useAppSelector((state) => state.exam.isLoadingAnExam)
  const { startAsync } = useStartExam()

  const { data: activeExam, isFetching: isFetchingActiveExam } =
    useActiveExamQuery(undefined, { refetchOnMountOrArgChange: 1 })

  if (userRole === rolesEnum.None) {
    return <UnauthenticatedComponent />
  }

  return (
    <Stack sx={{ paddingX: isMobile ? 3 : "10vw", paddingY: 4 }} gap={4}>
      <Ourbox>
        <ExamoHeader
          header={intl.formatMessage({
            id: "exams-header",
            defaultMessage: "Choose your exam",
          })}
          subtitle={intl.formatMessage({
            id: "exams-header-subtitle",
            defaultMessage:
              "Our operators make quizzes and tests to help you upgrade and test your skills.",
          })}
        />
        <CustomizedDialogs
          id="exams-page-filter"
          selectedTags={selectedTags}
          setSelectedTags={setSelectedTags}
          availableTags={availableTags || []}
          checkedFilterTags={checkedFilterTags}
          setCheckedFilterTags={setCheckedFilterTags}
        />
      </Ourbox>
      {isLoadingExams && <LoadingSpinner />}
      {!isLoadingExams && (!exams || exams.length === 0) && (
        <Typography>
          {intl.formatMessage({
            id: "no-exams-available",
            defaultMessage: "No exams available",
          })}
        </Typography>
      )}
      {exams && exams.length > 0 && (
        <ExamoCardsGrid>
          {exams.map((exam) => (
            <ExamoCard
              key={exam.id}
              type={ExamoTypesEnum.EXAM}
              useAssign={useExamAssign}
              isStartButtonDisabled={
                isLoadingAnExam ||
                isFetchingActiveExam ||
                (activeExam?.exam?.id !== undefined &&
                  exam.id !== activeExam.exam.id)
              }
              isResuming={
                activeExam?.exam?.id !== undefined &&
                exam.id === activeExam.exam.id
              }
              handleStart={() => startAsync(exam.id)}
              isLoading={isLoadingAnExam}
              title={exam.title}
              duration={exam.duration}
              tags={[
                ...new Set(exam.templates?.flatMap((et) => et.tags) || []),
              ]}
              numberOfQuestions={exam.templates.reduce(
                (total, current) => total + current.numberOfQuestions,
                0,
              )}
              deadline-start={exam["deadline-start"]}
              deadline-end={exam["deadline-end"]}
              i={exam.id}
            />
          ))}
        </ExamoCardsGrid>
      )}
    </Stack>
  )
})

最后一个是通过上面的代码映射的。所以就是 :

import { memo } from "react"
import * as React from "react"
import { useIntl } from "react-intl"
import AccessTimeIcon from "@mui/icons-material/AccessTime"
import ExpandMoreIcon from "@mui/icons-material/ExpandMore"
import MoreHorizIcon from "@mui/icons-material/MoreHoriz"
import Box from "@mui/material/Box"
import Card from "@mui/material/Card"
import MuiChip from "@mui/material/Chip"
import Collapse from "@mui/material/Collapse"
import Grid from "@mui/material/Grid"
import IconButton, { IconButtonProps } from "@mui/material/IconButton"
import Stack from "@mui/material/Stack"
import { styled } from "@mui/material/styles"
import Typography from "@mui/material/Typography"

import { ExamoTypesEnum } from "src/common/types/examo-types-enum"
import { useAssignType } from "src/common/types/use-assign-type"
import { useAppSelector } from "src/redux/hooks"
import { ExamoAssignTo } from "src/ui/examo/examo-assign-to"
import { ExamoStartDialogBtn } from "src/ui/examo/examo-start-btn"
interface props {
  duration: string | null
  title: string
  tags: string[] | null
  numberOfQuestions: number | null
  isLoading: boolean
  handleStart: () => void
  useAssign: useAssignType
  isStartButtonDisabled: boolean
  isResuming: boolean
  type: ExamoTypesEnum
  i: number
  "deadline-start": string
  "deadline-end": string
}
export const ExamoCard = memo(
  ({
    duration,
    tags,
    title,
    isLoading,
    numberOfQuestions,
    isStartButtonDisabled,
    isResuming,
    type,
    handleStart,
    useAssign,
    i,
    "deadline-end": deadlineEnd,
    "deadline-start": deadlineStart,
  }: props) => {
    console.log(deadlineStart)

    const intl = useIntl()
    const user = useAppSelector((state) => state.auth)
    const durationHours = duration?.split(":")[0]
    const durationMinutes = duration?.split(":")[1]
    // const [expanded, setExpanded] = React.useState(false)
    const [expandedId, setExpandedId] = React.useState(-1)

    // const handleExpandClick = () => {
    //   setExpanded(!expanded)
    // }
    const handleExpandClick = (i: number) => {
      setExpandedId(expandedId === i ? -1 : i)
    }

    const preventParentOnClick = (event: React.MouseEvent<HTMLElement>) => {
      event.stopPropagation()
    }

    interface ExpandMoreProps extends IconButtonProps {
      expand: boolean
    }

    const ExpandMore = styled((props: ExpandMoreProps) => {
      const { expand, ...other } = props

      return <IconButton {...other} />
    })(({ theme, expand }) => ({
      transform: !expand ? "rotate(0deg)" : "rotate(180deg)",
      transition: theme.transitions.create("transform", {
        duration: theme.transitions.duration.shortest,
      }),
    }))

    return (
      <Grid item xs={12} lg={6}>
        <Card
          onClick={() => handleExpandClick(i)}
          aria-expanded={expandedId === i}
          elevation={2}
          sx={{
            padding: "1rem",
            height: "100%",
            borderRadius: "1rem",
            border: "solid 1px var(--palette-grey-400)",
            transition: "all 0.1s ease-in-out",
            ":hover": {
              backgroundColor: "var(--palette-grey-100)",
              cursor: "pointer",
            },
          }}
        >
          <Stack direction="row" justifyContent="space-between">
            <Stack
              gap={numberOfQuestions ? 1.5 : 6}
              sx={{
                width: "100%",
              }}
            >
              <Stack
                direction="row"
                sx={{
                  justifyContent: "space-between",
                }}
              >
                <Typography
                  variant="h5"
                  sx={{ whiteSpace: "pre-wrap", wordBreak: "break-all" }}
                >
                  {title}
                </Typography>
                <ExpandMore expand={expandedId === i}>
                  <ExpandMoreIcon />
                </ExpandMore>
                <Stack
                  direction="row"
                  gap={1}
                  sx={{
                    justifyContent: "flex-end",
                    alignItems: "center",
                    marginTop: "-1.75rem",
                  }}
                >
                  <AccessTimeIcon />
                  <Typography
                    whiteSpace="nowrap"
                    variant="h6"
                  >{`${durationHours}h ${durationMinutes}m`}</Typography>
                </Stack>
              </Stack>
              <Collapse in={expandedId === i} timeout="auto" unmountOnExit>
                <Stack direction="row" gap={4}>
                  {numberOfQuestions && (
                    <Typography variant="h6">
                      {`${numberOfQuestions}  ${intl.formatMessage({
                        id: "questions",
                        defaultMessage: "Questions",
                      })}`}
                    </Typography>
                  )}
                </Stack>
                <Stack
                  direction="row"
                  sx={{ flexWrap: "wrap", gap: 1, marginTop: "1rem" }}
                >
                  {tags?.map((t, index) => (
                    <MuiChip
                      key={index}
                      label={t}
                      variant="filled"
                      sx={{ fontWeight: "bold" }}
                      color="secondary"
                      size="small"
                    />
                  ))}
                </Stack>
              </Collapse>
            </Stack>
            <Stack
              sx={{ marginTop: "-0.5rem" }}
              justifyContent="space-between"
              alignItems="center"
              spacing={user.role === "Operator" ? 0.1 : 1}
            >
              <MoreHorizIcon sx={{ marginLeft: "2rem" }} />
              <Box onClick={preventParentOnClick}>
                <Stack sx={{ marginLeft: "1.5rem" }}>
                  {user.role === "Operator" && (
                    <ExamoAssignTo useAssign={useAssign} title={title} />
                  )}
                </Stack>
              </Box>
              <Box onClick={preventParentOnClick}>
                <ExamoStartDialogBtn
                  type={type}
                  isResuming={isResuming}
                  handleStart={handleStart}
                  isLoading={isLoading}
                  isDisabled={isStartButtonDisabled}
                />
              </Box>
            </Stack>
          </Stack>
        </Card>
      </Grid>
    )
  },

)

To sum up guys, I want to also fetch deadlineStart and deadlineEnd but i can't. I think problem is in last file or second to last, because maybe am not defining them properly in interface props in last code. And also i almost forgot to mention that when I try to console.log(deadlineStart) in the last code it says undefined in the browser. Edited Network Pic : enter image description here

here is screenshot when i console log single exams : enter image description here


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Redux Toolkit 查询未获取数据 的相关文章