Как ввести асинхронное действие и функциональный компонент React в Typescript? - PullRequest
0 голосов
/ 21 января 2020

У меня довольно приятные настройки c. Мой функциональный компонент Images запускает функцию извлечения данных fetchImages с помощью ловушки React useEffect. fetchImages настроена как асинхронная c функция, поскольку она ожидает разрешения, возвращенного из imageAction, прежде чем отправит это действие моему редуктору. Аналогично, imageAction - это асинхронная c функция, так как она ожидает разрешения от 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'.

Как мне правильно введите все мои функции? Правильно ли я настроил свои функции asyn c? Не слишком ли много асинхронных / ожидающих цепочек? Я не уверен, как печатать, когда все эти функции asyn c возвращают 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;

Ответы [ 2 ]

0 голосов
/ 21 января 2020

Как уже упоминалось в моем комментарии, компоненты не могут asyn c. Вам необходимо переместить асин c логи c внутрь эффекта:

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;

Вы должны рассмотреть возможность передачи зависимостей эффекта, хотя, как и в текущей форме, эффект выполняется при каждом обновлении

0 голосов
/ 21 января 2020

Функциональные компоненты не могут быть асинхронными c. Как только вы добавляете в него asyn c, он возвращает Обещание, которого React не ожидает. ОДНАКО, если это действительно работает, то вы, вероятно, можете просто утверждать, что это FunctionalComponent ...

Вместо

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

Вы можете сказать

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

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

Но даже если это работает, это не лучшая реализация.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...