簡體   English   中英

嘗試從 GraphQL API 獲取數據,然后將其作為道具傳遞給組件

[英]Trying to fetch data from a GraphQL API and then pass it as props to a component

我現在很喜歡 GraphQL 和 TypeScript,所以我正在嘗試通過使用這個 API https://github.com/trevorblades/countries來學習它。 我試圖從 API 獲取數據到我的 HomeComponent 中的 React 應用程序,然后將數據傳遞到我的 CountryTable 組件,它是 MUI 庫中的一個表組件。 但是我得到這些錯誤,因為“類型參數不可分配給參數”,“TypeError:countries.map 不是函數”。

這就是我的 HomeComponent 的樣子:

import { Grid } from '@mui/material';
import Typography from '@mui/material/Typography';
import { ApolloClient, InMemoryCache, gql, useLazyQuery, ApolloProvider, useQuery,     TypedDocumentNode} from '@apollo/client';
import { useEffect, useState } from 'react';
import React from 'react';
import CountryTable from '../components/CountryTable';

const client = new ApolloClient({
  cache: new InMemoryCache(),
  uri: 'https://countries.trevorblades.com'
});

const LIST_COUNTRIES = gql`
  query getCountries {
    countries {
      name
      code
      capital
  }}`;

export interface Country {
  name: string;
  code: string;
  capital: string;
}

export interface Countries {
  getAllCountries: Country[];
}

export default function Home() {
  const {loading, data, error} = useQuery<Countries>(LIST_COUNTRIES, {client});
  const [allcountries, setAllcountries] = useState([]);

  useEffect(() => {
    setAllcountries(data);
  }, [data])

  if (loading) return <p>Loading...</p>;
  if (error) return <p>Error : {error.message}</p>;

  return (
    <ApolloProvider client={client}>
    <Grid container alignItems="center" justifyContent="center">
      <Grid item>
        <CountryTable countries={allcountries}/>
      </Grid>
    </Grid>
    </ApolloProvider>
  )
}

這是我的 CountryTable 組件:

import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
import { Country } from "../pages";

export interface CountryProps {
    countries: Country[];
}

export default function CountryTable({countries}: CountryProps) {
    return(
        <TableContainer component={Paper}>
            <Table sx={{ minWidth: 650 }} aria-label="simple table">
                <TableHead>
                    <TableRow>
                        <TableCell align="right">Name</TableCell>
                        <TableCell align="right">Code</TableCell>
                        <TableCell align="right">Capital</TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {countries?.map((row: any) => (
                        <TableRow key={row.name}>
                        <TableCell align="right">{row.name}</TableCell>
                        <TableCell align="right">{row.code}</TableCell>
                        <TableCell align="right">{row.capital}</TableCell>
                    </TableRow>
                ))}
                </TableBody>
            </Table>
        </TableContainer>
    );
}

項目結構: ProjectStructure

您在包裝ApolloProvider的同一級別調用useQuery掛鈎。

// Home.js
const {loading, data, error} = useQuery<Countries>(LIST_COUNTRIES, {client}); // 👈 same level
...
...
return (
    <ApolloProvider client={client}> {/* 👈 Same level */}
      ..
      ..
    </ApolloProvider>
)

將您擁有的useQuery掛鈎從Home移動到CountryTable組件的原因是因為現在

  • CountryTableApolloProvider里面。
  • useQuery掛鈎可以訪問它需要的client數據,這在之前它們被定義在同一級別時是不可能的。

要使其在同一級別工作,請將ApolloProvider上移一個級別。

這可以是

  • Home組件的父組件,如果有的話,
  • _app.js組件,如果你使用NextJS [1]

參考:

  1. https://nextjs.org/docs/advanced-features/custom-app

我無法從 GraphQL API 獲取數據的問題是因為我正在檢索的數據是一個整體 object 和我用來保存數據的 useState 變量,因此我可以將它作為道具傳遞給另一個component 是接口 Country 的 ArrayType。 所以我刪除了接口 Countries,然后將我的 const variabel 定義如下:

  const {loading, data, error} = useQuery<{countries: Country[]}>(LIST_COUNTRIES, {client});
  const [allcountries, setAllcountries] = useState<Country[]>();

然后我接收道具的組件具有以下代碼:

import { Box, Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material";
import Link from "next/link";
import { useRouter } from "next/router";
import { FC } from "react";
import { Country } from "../pages";

export interface CountryProps {
    countries: Country[] | undefined;
}


const CountryTable: FC<CountryProps> = ({countries}) => {
    const router = useRouter();

    return(
        <TableContainer component={Paper}>
            <Table sx={{ minWidth: 650 }} aria-label="simple table">
                <TableHead>
                    <TableRow>
                        <TableCell align="right">Name</TableCell>
                        <TableCell align="right">Code</TableCell>
                        <TableCell align="right">Capital</TableCell>
                    </TableRow>
                </TableHead>
                <TableBody>
                    {countries?.map(({name, code, capital}: Country) => (
                        <TableRow key={name}>
                        <TableCell align="right">
                        <Box>
                            <Link href={{pathname: "/detail/[name]", query: {name: name}}}>
                                {name}
                            </Link>
                        </Box>
                        </TableCell>
                        <TableCell align="right">{code}</TableCell>
                        <TableCell align="right">{capital}</TableCell>
                    </TableRow>
                ))}
                </TableBody>
            </Table>
        </TableContainer>
    );
}

export default CountryTable;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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