簡體   English   中英

類型錯誤:JSX 元素類型 '{} | null | undefined' 不是 JSX 元素的構造函數 function

[英]Type error: JSX element type '{} | null | undefined' is not a constructor function for JSX elements

我有一個名為HandleQuery的 React 組件,它處理 Apollo GraphQL 查詢的結果:

import React, { ReactNode } from 'react';

import { CenteredMessage } from './centered-message';

export interface HandleQueryProps {
    loading: boolean,
    error?: Error,
    children: ReactNode
}

export const HandleQuery = ({ loading, error, children }: HandleQueryProps) => {
    if (loading) {
        return <CenteredMessage>Loading...</CenteredMessage>;
    }

    if (error) {
        return <CenteredMessage>{error.message}</CenteredMessage>;
    }

    return children;
};

當此組件在另一個組件中使用時,它不會編譯:

import React from 'react';

import { useQuery } from 'react-apollo-hooks';
import gql from 'graphql-tag';
import { HandleQuery } from '..';
import { MutationType } from '../../graphql-types';
import { AuthorsPanel } from './authors-panel';
import { GET_AUTHORS } from './authors-queries';
import { AuthorMutated } from './__generated__/AuthorMutated';

export class AuthorsContainer extends React.Component {
    render() {
        const { loading, error, data } = useQuery(GET_AUTHORS);
        return (
            <!-- THIS LINE PRODUCES A COMPILER ERROR -->
            <HandleQuery loading={loading} error={error}>
                <AuthorsPanel data={data} />
            </HandleQuery>
        );
    }
}

使用上面的HandleQuery會產生以下錯誤:

類型錯誤:JSX 元素類型 '{} | null | undefined' 不是 JSX 元素的構造函數 function。 類型“undefined”不可分配給類型“Element | 無效的'。 TS2605

這是什么意思,我怎樣才能擺脫它?

更新

將 AuthorsContainer 轉換為 function 組件並不能消除錯誤:

export const AuthorsContainer = () => {
    const { loading, error, data } = useQuery(GET_AUTHORS);
    return (
        <HandleQuery loading={loading} error={error}>
            <AuthorsPanel data={data} />
        </HandleQuery>
    );
};

更新 2實施了@FredyC 的建議:

import React from 'react';

import { CenteredMessage } from './centered-message';

export interface HandleQueryProps {
    loading: boolean;
    error?: Error;
}

export const HandleQuery: React.FC<HandleQueryProps> = ({
    loading,
    error,
    children
}) => {
    if (loading) {
        return <CenteredMessage>Loading...</CenteredMessage>;
    }

    if (error) {
        return <CenteredMessage>{error.message}</CenteredMessage>;
    }

    return children;
};

現在容器組件上的錯誤已經消失,但是HandleQuery組件上彈出了一個新的編譯器錯誤:

Type error: Type '({ loading, error, children }: PropsWithChildren<HandleQueryProps>) => {} | null | undefined' is not assignable to type 'FunctionComponent<HandleQueryProps>'.
  Type '{} | null | undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
    Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.  TS2322

關於 ReactNode 有一個長期問題。 我不明白具體細節,但它是 TypeScript 本身固有的東西,正在研究中。

無論哪種方式,解決方案都應該很容易。 不要將 ReactNode 與功能組件一起使用 :) children屬性隱式包含在 React.FC 類型中。

返回的孩子也有同樣的問題。 如果您願意,可以通過包裝到<React.Fragment><div>來克服它,但由於這只是一個類型錯誤,您可以說服 TypeScript 您知道自己在做什么:)

import React, { ReactNode } from 'react';

import { CenteredMessage } from './centered-message';

export interface HandleQueryProps {
    loading: boolean,
    error?: Error,
}

export const HandleQuery: React.FC<HandleQueryProps> = ({ loading, error, children }) => {
    if (loading) {
        return <CenteredMessage>Loading...</CenteredMessage>;
    }

    if (error) {
        return <CenteredMessage>{error.message}</CenteredMessage>;
    }

    return children as ReactElement<any>;
};

在這種情況下,它可以更容易簡單地定義childrenReactElement如果我不排除一些東西。

export interface HandleQueryProps {
    loading: boolean,
    error?: ApolloError,
    children: ReactElement
}

切換ReactNodeJSX.Element解決了此類問題。

根據React 上的相關 github issue ,建議功能組件使用JSX.Element而不是ReactNode

您可以在JSX.Element -cheatsheets/react page 中查看JSX.ElementReactNode的詳細信息。

我對這種情況的解決方案,它適用於Typescript Generics

查詢包裝器.ts

import { QueryResult } from "@apollo/client/react/types/types";

interface Props<TData, TVariables> {
  query: QueryResult<TData, TVariables>;
  children: (data: TData) => any;
}

export function QueryWrapper<TData, TVariables>({ query, children }: Props<TData, TVariables>) {
  if (query.loading) {
    return "loading...";
  }

  if (query.error) {
    return query.error.message;
  }

  if (!query.data) {
    return "Data is empty"
  }

  return children(query.data as TData);
}

用法:

const recipeQuery = useQuery<{ recipes: Recipe[] }>(GET_RECIPES);

<QueryWrapper query={recipeQuery}>
    {({recipes}) => (
       JSON.stringify(recipes)
    )}
</QueryWrapper>

對我來說,這個命令解決了這個問題:

rm -rf node_modules && rm yarn.lock && yarn

暫無
暫無

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

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