useReducer中用于返回参数的通用类型 [英] Generic type in useReducer for a returned parameter

查看:44
本文介绍了useReducer中用于返回参数的通用类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个自定义钩子,以从API中获取一些数据.我希望返回的数据尽可能是类型安全的.可以使用泛型吗?

I am writing a custom hook to fetch some data from an API. I would like the returned data to be type-safe if possible. Can this be done with generics?

type Action = { type: 'PENDING' } | { type: 'SUCCESS'; payload: any } | { type: 'FAIL' };

interface State {
  isLoading: boolean;
  isError: boolean;
  data: any;
}

const dataFetchReducer = (state: State, action: Action): State => {
  switch (action.type) {
    case 'PENDING':
      return {
        ...state,
        isLoading: true,
      };
    case 'SUCCESS': {
      return {
        ...state,
        isLoading: false,
        isError: false,
        data: action.payload,
      };
    }
    case 'FAIL':
      return {
        ...state,
        isLoading: false,
        isError: true,
      };
    default:
      throw new Error('Action not supported');
  }
};

const baseUrl = 'http://localhost:4000';

function useDataFetchFromAPI(initUrl: string, initData: any) {
  const [url, setUrl] = useState(`${baseUrl}${initUrl}`);
  const [state, dispatch] = useReducer(dataFetchReducer, {
    isLoading: false,
    isError: false,
    data: initData,
  });

  // effect only runs if url changes
  // see deps array (2nd argument)
  useEffect(() => {
    const fetchData = async () => {
      dispatch({ type: 'PENDING' });
      try {
        const result = await axios(url);
        dispatch({ type: 'SUCCESS', payload: result.data });
      } catch (error) {
        dispatch({ type: 'FAIL' });
      }
    };
    fetchData();
  }, [url]);
  const executeFetch = (url: string) => {
    setUrl(url);
  };
  return { ...state, executeFetch };
}

用法为 useDataFetchFromAPI('url',[]).

我认为您可以执行 useDataFetchFromAPI<之类的操作.SomeType>()并通过它,但我不确定实现方式.

I figured you could do something like useDataFetchFromAPI < SomeType > () and pass it through but I'm unsure on the implementation.

推荐答案

import axios, { AxiosPromise } from 'axios';
import { FC, useEffect, useReducer, useState } from 'react';

type Action<T> = { type: 'PENDING' } | { type: 'SUCCESS'; payload: T } | { type: 'FAIL' };

interface State<T> {
    isLoading: boolean;
    isError: boolean;
    data: T;
}

const createDataFetchReducer = <T>() => (state: State<T>, action: Action<T>): State<T> => {
    switch (action.type) {
        case 'PENDING':
            return {
                ...state,
                isLoading: true,
            };
        case 'SUCCESS': {
            return {
                ...state,
                isLoading: false,
                isError: false,
                data: action.payload,
            };
        }
        case 'FAIL':
            return {
                ...state,
                isLoading: false,
                isError: true,
            };
        default:
            throw new Error('Action not supported');
    }
};

const baseUrl = 'http://localhost:4000';

function useDataFetchFromAPI<T>(initUrl: string, initData: T) {
    const [url, setUrl] = useState(`${baseUrl}${initUrl}`);
    const dataFetchReducer = createDataFetchReducer<T>();
    const [state, dispatch] = useReducer(dataFetchReducer, {
        isLoading: false,
        isError: false,
        data: initData,
    });

    // effect only runs if url changes
    // see deps array (2nd argument)
    useEffect(() => {
        const fetchData = async () => {
            dispatch({ type: 'PENDING' });
            try {
                const axiosPromise: AxiosPromise<T> = axios(url);
                const result = await axiosPromise;
                dispatch({ type: 'SUCCESS', payload: result.data });
            } catch (error) {
                dispatch({ type: 'FAIL' });
            }
        };
        fetchData();
    }, [url]);
    const executeFetch = (url: string) => {
        setUrl(url);
    };
    return { ...state, executeFetch };
}

const MyComponent: FC<{}> = props => {
    type Response = { foo: number; }
    const x = useDataFetchFromAPI<Response>('/foo', {
        foo: 1
    });
    x.data.foo;

    return null;
};

这篇关于useReducer中用于返回参数的通用类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆