React+GraphQL+TypeScript数据传递报错求助:类型不匹配与map调用失败
问题解决:GraphQL + TypeScript + React 数据传递错误修复
核心错误原因
- 类型接口不匹配:
Countries接口定义了getAllCountries字段,但GraphQL查询返回的结构是{ countries: Country[] },字段名不匹配导致TypeScript类型校验失败。 - 数据传递错误:直接将整个
data对象(而非内部的countries数组)存入状态,子组件拿到的是对象而非数组,调用map方法自然报错。 - Apollo上下文错误:
useQuery必须在ApolloProvider的上下文范围内执行,当前代码中useQuery先于ApolloProvider渲染,导致无法获取客户端实例。 - 冗余状态逻辑:无需额外用
useState和useEffect存储数据,直接使用useQuery返回的结果即可。
分步修复代码
1. 修正类型定义(Home组件)
将Countries接口的字段改为countries,匹配GraphQL查询结果:
export interface Countries { countries: Country[]; }
2. 调整ApolloProvider位置(移到应用入口)
创建/修改App.tsx,将ApolloProvider作为根组件包裹Home,确保所有组件都能访问GraphQL客户端:
import { ApolloClient, InMemoryCache, ApolloProvider } from '@apollo/client'; import Home from './pages/Home'; const client = new ApolloClient({ cache: new InMemoryCache(), uri: 'https://countries.trevorblades.com' }); function App() { return ( <ApolloProvider client={client}> <Home /> </ApolloProvider> ); } export default App;
3. 简化Home组件逻辑
移除内部的客户端定义和ApolloProvider,直接传递正确的数组给子组件:
import { Grid } from '@mui/material'; import { useQuery, gql } from '@apollo/client'; import React from 'react'; import CountryTable from '../components/CountryTable'; const LIST_COUNTRIES = gql` query getCountries { countries { name code capital }}`; export interface Country { name: string; code: string; capital: string; } export interface Countries { countries: Country[]; } export default function Home() { const { loading, data, error } = useQuery<Countries>(LIST_COUNTRIES); if (loading) return <p>加载中...</p>; if (error) return <p>错误: {error.message}</p>; return ( <Grid container alignItems="center" justifyContent="center"> <Grid item> <CountryTable countries={data.countries} /> </Grid> </Grid> ) }
4. 优化CountryTable组件
修正类型引用,替换any为正确的Country类型,同时处理无首都的情况:
import { Paper, Table, TableBody, TableCell, TableContainer, TableHead, TableRow } from "@mui/material"; import { Country } from "../pages/Home"; export interface CountryProps { countries: Country[]; } export default function CountryTable({ countries }: CountryProps) { return( <TableContainer component={Paper}> <Table sx={{ minWidth: 650 }} aria-label="国家列表表格"> <TableHead> <TableRow> <TableCell align="right">名称</TableCell> <TableCell align="right">代码</TableCell> <TableCell align="right">首都</TableCell> </TableRow> </TableHead> <TableBody> {countries.map((row: Country) => ( <TableRow key={row.code}> <TableCell align="right">{row.name}</TableCell> <TableCell align="right">{row.code}</TableCell> <TableCell align="right">{row.capital || '无'}</TableCell> </TableRow> ))} </TableBody> </Table> </TableContainer> ); }
额外说明
- 用国家代码
code作为key比名称更可靠,避免同名国家导致的渲染问题。 - 部分国家没有首都,添加
|| '无'处理空值,避免显示空白。
内容的提问来源于stack exchange,提问作者menab
相关产品推荐
相关产品推荐

