【问题标题】:How to type an asynchronous action and functional React component in Typescript?如何在 Typescript 中键入异步操作和功能性 React 组件?
【发布时间】:2020-05-06 22:47:32
【问题描述】:

我有一个非常基本的设置。我的功能组件 Images 使用 React 钩子 useEffect 触发数据获取函数 fetchImagesfetchImages 被设置为一个异步函数,因为它等待从 imageAction 返回的承诺解决,然后再将这个操作分派给我的减速器。同样,imageAction 是一个异步函数,因为它等待来自imageRequest 的承诺来解决。不幸的是,我从 Typescript 收到了一些编译错误。

const Images: 下的波浪线显示此错误:

src/components/images.tsx(42,7): error TS2322: Type '() => Promise<Element>' is not assignable to type 'FunctionComponent<{}>'.
  Type 'Promise<Element>' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | any | (new (props: any) =>...'.
    Property 'type' is missing in type 'Promise<Element>'.

fetchImages(params, imageDispatch) 下的波浪线显示此错误:

src/components/images.tsx(49,13): error TS2345: Argument of type '() => Promise<void>' is not assignable to parameter of type 'EffectCallback'.
  Type 'Promise<void>' is not assignable to type 'void | (() => void)'.
    Type 'Promise<void>' is not assignable to type '() => void'.
      Type 'Promise<void>' provides no match for the signature '(): void'.

如何正确键入我的所有函数?我是否正确设置了异步功能?是否有太多的链式异步/等待?当所有这些异步函数返回 Promises 时,我不确定如何输入内容...

import React, { useReducer, useEffect } from 'react';
import axios, { AxiosResponse } from 'axios';
import * as types from '../types';
import * as imageStore from '../reducers/image-reducer';

export type Images = string[];

export interface ImagesPayload {
  images: Images;
}

export interface ImagesAction {
  type: string;
  payload: ImagesPayload;
}

export interface Params {
  page: number;
}

const baseURL = 'http://0.0.0.0:5000/api/v1/';
const api = axios.create({ baseURL });

const imageRequest = async (params: Params): Promise<ImagesPayload> => {
  const response: AxiosResponse<types.ImagesPayload> = await api.get('/images', { params });
  const payload = response.data;
  return payload;
};

const imageAction = async (params: Params): Promise<ImagesAction> => {
  const payload = await imageRequest(params);
  return {
    type: 'LOAD_IMAGES',
    payload,
  };
};

const fetchImages = async (params: Params, dispatch: Function): Promise<void> => {
  dispatch(await imageAction(params));
};

const Images: React.FunctionComponent = async () => {
  const [{ images }, imageDispatch] = useReducer(
    imageStore.reducer,
    imageStore.initialState,
  );
  const size = 'L';
  const params: types.Params = { page: 1, size };
  useEffect(() => fetchImages(params, imageDispatch));
  return (
    <div className="content">
      { images.map((image: string) => <img key={image} className="image" src={image} alt="" />) }
    </div>
  );
};

export default Images;

【问题讨论】:

  • 据我所知,函数组件不能是异步的。另一方面的影响可能是

标签: reactjs typescript asynchronous


【解决方案1】:

功能组件不能是异步的。一旦你向它添加异步,它就会返回一个 Promise,这是 React 不期望的。但是,如果它确实在工作,那么您可能只是断言它是一个功能组件......

代替

const Images: React.FunctionComponent = async () => {

你可以说

const Images = async () => { } as React.FunctionComponent;

const Images = async () => { } as unknown as React.FunctionComponent;

但即使这样可行,也不是最好的实现方式。

【讨论】:

    【解决方案2】:

    正如我在评论中提到的,组件不能异步。您需要在效果内移动异步逻辑:

    import React, { useReducer, useEffect } from 'react';
    import axios, { AxiosResponse } from 'axios';
    import * as types from '../types';
    import * as imageStore from '../reducers/image-reducer';
    
    export type Images = string[];
    
    export interface ImagesPayload {
      images: Images;
    }
    
    export interface ImagesAction {
      type: string;
      payload: ImagesPayload;
    }
    
    export interface Params {
      page: number;
    }
    
    const baseURL = 'http://0.0.0.0:5000/api/v1/';
    const api = axios.create({ baseURL });
    
    const imageRequest = async (params: Params): Promise<ImagesPayload> => {
      const response: AxiosResponse<types.ImagesPayload> = await api.get('/images', { params });
      const payload = response.data;
      return payload;
    };
    
    const imageAction = async (params: Params): Promise<ImagesAction> => {
      const payload = await imageRequest(params);
      return {
        type: 'LOAD_IMAGES',
        payload,
      };
    };
    
    const fetchImages = async (params: Params, dispatch: Function): Promise<void> => {
      dispatch(await imageAction(params));
    };
    
    const Images: React.FunctionComponent = () => {
      const [{ images }, imageDispatch] = useReducer(
        imageStore.reducer,
        imageStore.initialState,
      );
      const size = 'L';
      const params: types.Params = { page: 1, size };
      useEffect(async () => fetchImages(params, imageDispatch));
      return (
        <div className="content">
          { images.map((image: string) => <img key={image} className="image" src={image} alt="" />) }
        </div>
      );
    };
    
    export default Images;
    

    您应该考虑传递效果依赖项,尽管在当前形式下,效果会在每次更新时执行

    【讨论】:

      猜你喜欢
      • 2021-03-08
      • 2017-07-02
      • 1970-01-01
      • 1970-01-01
      • 2020-06-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-10-23
      相关资源
      最近更新 更多