如何使用打字稿中的反应钩子设置graphql数据?
Posted
技术标签:
【中文标题】如何使用打字稿中的反应钩子设置graphql数据?【英文标题】:How to set graphql data using react hooks in typescript? 【发布时间】:2020-08-09 22:06:24 【问题描述】:我有一个组件,我正在尝试使用 apollo 从 graphql 服务 (https://rickandmortyapi.com) 获取数据,一切正常,但我无法使用 react hooks 设置数据:
const [characters, setCharacters] = useState<Character[]>([]);
const data, error, loading, refetch = useCharactersListQuery(
variables: name: String(search),
onCompleted: (data)=>
//here I can see data very well
console.log(data.characters!)
//this line gives me an ERROR
setCharacters(data.characters!.results!)
);
当我尝试使用 setCharacters 方法设置数据时发生错误
TS2345: 'Maybe[]' 不是 可分配给“SetStateAction”类型的参数。类型 '也许[]' 不能分配给类型'Character[]'。 键入'也许' 不可分配给类型 '特点'。类型“null”不能分配给类型“Character”。
我所有类型的大型 graphql.tsx 文件
import gql from 'graphql-tag';
import * as React from 'react';
import * as ApolloReactCommon from '@apollo/react-common';
import * as ApolloReactComponents from '@apollo/react-components';
import * as ApolloReactHoc from '@apollo/react-hoc';
import * as ApolloReactHooks from '@apollo/react-hooks';
export type Maybe<T> = T | null;
export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>;
/** All built-in and custom scalars, mapped to their actual values */
export type Scalars =
ID: string;
String: string;
Boolean: boolean;
Int: number;
Float: number;
/** The `Upload` scalar type represents a file upload. */
Upload: any;
;
export type Query =
__typename?: 'Query';
/** Get a specific character by ID */
character?: Maybe<Character>;
/** Get the list of all characters */
characters?: Maybe<Characters>;
/** Get a specific locations by ID */
location?: Maybe<Location>;
/** Get the list of all locations */
locations?: Maybe<Locations>;
/** Get a specific episode by ID */
episode?: Maybe<Episode>;
/** Get the list of all episodes */
episodes?: Maybe<Episodes>;
;
export type QueryCharacterArgs =
id?: Maybe<Scalars['ID']>;
;
export type QueryCharactersArgs =
page?: Maybe<Scalars['Int']>;
filter?: Maybe<FilterCharacter>;
;
export type QueryLocationArgs =
id?: Maybe<Scalars['ID']>;
;
export type QueryLocationsArgs =
page?: Maybe<Scalars['Int']>;
filter?: Maybe<FilterLocation>;
;
export type QueryEpisodeArgs =
id?: Maybe<Scalars['ID']>;
;
export type QueryEpisodesArgs =
page?: Maybe<Scalars['Int']>;
filter?: Maybe<FilterEpisode>;
;
export type Character =
__typename?: 'Character';
/** The id of the character. */
id?: Maybe<Scalars['ID']>;
/** The name of the character. */
name?: Maybe<Scalars['String']>;
/** The status of the character ('Alive', 'Dead' or 'unknown'). */
status?: Maybe<Scalars['String']>;
/** The species of the character. */
species?: Maybe<Scalars['String']>;
/** The type or subspecies of the character. */
type?: Maybe<Scalars['String']>;
/** The gender of the character ('Female', 'Male', 'Genderless' or 'unknown'). */
gender?: Maybe<Scalars['String']>;
/** The character's origin location */
origin?: Maybe<Location>;
/** The character's last known location */
location?: Maybe<Location>;
/**
* Link to the character's image.
* All images are 300x300px and most are medium shots or portraits since they are intended to be used as avatars.
*/
image?: Maybe<Scalars['String']>;
/** Episodes in which this character appeared. */
episode?: Maybe<Array<Maybe<Episode>>>;
/** Time at which the character was created in the database. */
created?: Maybe<Scalars['String']>;
;
export type Location =
__typename?: 'Location';
/** The id of the location. */
id?: Maybe<Scalars['ID']>;
/** The name of the location. */
name?: Maybe<Scalars['String']>;
/** The type of the location. */
type?: Maybe<Scalars['String']>;
/** The dimension in which the location is located. */
dimension?: Maybe<Scalars['String']>;
/** List of characters who have been last seen in the location. */
residents?: Maybe<Array<Maybe<Character>>>;
/** Time at which the location was created in the database. */
created?: Maybe<Scalars['String']>;
;
export type Episode =
__typename?: 'Episode';
/** The id of the episode. */
id?: Maybe<Scalars['ID']>;
/** The name of the episode. */
name?: Maybe<Scalars['String']>;
/** The air date of the episode. */
air_date?: Maybe<Scalars['String']>;
/** The code of the episode. */
episode?: Maybe<Scalars['String']>;
/** List of characters who have been seen in the episode. */
characters?: Maybe<Array<Maybe<Character>>>;
/** Time at which the episode was created in the database. */
created?: Maybe<Scalars['String']>;
;
export type FilterCharacter =
name?: Maybe<Scalars['String']>;
status?: Maybe<Scalars['String']>;
species?: Maybe<Scalars['String']>;
type?: Maybe<Scalars['String']>;
gender?: Maybe<Scalars['String']>;
;
export type Characters =
__typename?: 'Characters';
info?: Maybe<Info>;
results?: Maybe<Array<Maybe<Character>>>;
;
export type Info =
__typename?: 'Info';
/** The length of the response. */
count?: Maybe<Scalars['Int']>;
/** The amount of pages. */
pages?: Maybe<Scalars['Int']>;
/** Number of the next page (if it exists) */
next?: Maybe<Scalars['Int']>;
/** Number of the previous page (if it exists) */
prev?: Maybe<Scalars['Int']>;
;
export type FilterLocation =
name?: Maybe<Scalars['String']>;
type?: Maybe<Scalars['String']>;
dimension?: Maybe<Scalars['String']>;
;
export type Locations =
__typename?: 'Locations';
info?: Maybe<Info>;
results?: Maybe<Array<Maybe<Location>>>;
;
export type FilterEpisode =
name?: Maybe<Scalars['String']>;
episode?: Maybe<Scalars['String']>;
;
export type Episodes =
__typename?: 'Episodes';
info?: Maybe<Info>;
results?: Maybe<Array<Maybe<Episode>>>;
;
export enum CacheControlScope
Public = 'PUBLIC',
Private = 'PRIVATE'
export type CharactersListQueryVariables =
name?: Maybe<Scalars['String']>;
;
export type CharactersListQuery = (
__typename?: 'Query'
& characters?: Maybe<(
__typename?: 'Characters'
& info?: Maybe<(
__typename?: 'Info'
& Pick<Info, 'count'>
)>, results?: Maybe<Array<Maybe<(
__typename?: 'Character'
& Pick<Character, 'id' | 'name' | 'image'>
)>>>
)>
);
export const CharactersListDocument = gql`
query charactersList($name: String)
characters(page: 1, filter: name: $name)
info
count
results
id
name
image
`;
export type CharactersListComponentProps = Omit<ApolloReactComponents.QueryComponentOptions<CharactersListQuery, CharactersListQueryVariables>, 'query'>;
export const CharactersListComponent = (props: CharactersListComponentProps) => (
<ApolloReactComponents.Query<CharactersListQuery, CharactersListQueryVariables> query=CharactersListDocument ...props />
);
export type CharactersListProps<TChildProps = , TDataName extends string = 'data'> =
[key in TDataName]: ApolloReactHoc.DataValue<CharactersListQuery, CharactersListQueryVariables>
& TChildProps;
export function withCharactersList<TProps, TChildProps = , TDataName extends string = 'data'>(operationOptions?: ApolloReactHoc.OperationOption<
TProps,
CharactersListQuery,
CharactersListQueryVariables,
CharactersListProps<TChildProps, TDataName>>)
return ApolloReactHoc.withQuery<TProps, CharactersListQuery, CharactersListQueryVariables, CharactersListProps<TChildProps, TDataName>>(CharactersListDocument,
alias: 'charactersList',
...operationOptions
);
;
/**
* __useCharactersListQuery__
*
* To run a query within a React component, call `useCharactersListQuery` and pass it any options that fit your needs.
* When your component renders, `useCharactersListQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const data, loading, error = useCharactersListQuery(
* variables:
* name: // value for 'name'
* ,
* );
*/
export function useCharactersListQuery(baseOptions?: ApolloReactHooks.QueryHookOptions<CharactersListQuery, CharactersListQueryVariables>)
return ApolloReactHooks.useQuery<CharactersListQuery, CharactersListQueryVariables>(CharactersListDocument, baseOptions);
export function useCharactersListLazyQuery(baseOptions?: ApolloReactHooks.LazyQueryHookOptions<CharactersListQuery, CharactersListQueryVariables>)
return ApolloReactHooks.useLazyQuery<CharactersListQuery, CharactersListQueryVariables>(CharactersListDocument, baseOptions);
export type CharactersListQueryHookResult = ReturnType<typeof useCharactersListQuery>;
export type CharactersListLazyQueryHookResult = ReturnType<typeof useCharactersListLazyQuery>;
export type CharactersListQueryResult = ApolloReactCommon.QueryResult<CharactersListQuery, CharactersListQueryVariables>;
我不完全理解类型有什么问题以及如何解决它?
【问题讨论】:
【参考方案1】:在您的类型定义中,您已将 Characters 响应定义为:
export type Characters =
__typename?: 'Characters';
info?: Maybe<Info>;
results?: Maybe<Array<Maybe<Character>>>;
;
这意味着即使你使用!
命令,强制TS相信data.characters!.results!
是一个数组并且不是未定义的,数组elements仍然可能是未定义的(Array<Maybe<Character>>
)。
您可以通过以下方式之一解决此问题:
确保您的 API 始终返回有效字符,并将返回类型更改为 Array<Character>
将您的 useState
定义更改为 useState<Maybe<Character>[]>([]);
并在渲染中处理 null
字符(这对我来说似乎很奇怪,但很好)
直接在onCompleted
中过滤null
字符
但是,我认为您的查询弄错了。从useCharactersListQuery
解构得到的data
变量已经包含了API 响应,你不需要使用另一个本地React 状态来存储它。
【讨论】:
以上是关于如何使用打字稿中的反应钩子设置graphql数据?的主要内容,如果未能解决你的问题,请参考以下文章