reactjs - 如何使变量的类型为未知或 'Movie' 分配?

标签 reactjs typescript

我正在开发一个钩子(Hook),我可以在其中传递一个发出 Web 请求的函数,它返回 isLoading , dataerror .

const [isLoading, data, error] = useApi(getMovie, idMovie, someAction);
基本上我有一个接收 3 个参数的钩子(Hook)( useApi ):
  • 解析 Web 请求的函数
  • 这个web请求的参数
  • 最后是对回调的调用。

  • 我像这样使用它:
    const idMovie = { _id: "3" };
    // callback function
    const someAction = (data: unknown) => {
     // do something
     return data;
    };
    
    const [isLoading, data, error] = useApi(getMovie, idMovie, someAction);
    
    useApi.tsx
    import { AxiosPromise, AxiosResponse } from 'axios';
    import { useState, useEffect } from 'react';
    const useApi = (
        apiFunction: (params: unknown) => AxiosPromise,
        params = {},
        callback: (data: unknown) => void
    ): [boolean, unknown, null | string] => {
        const [data, setData] = useState(null);
        const [isLoading, setIsLoading] = useState(true);
        const [error, setError] = useState<null | string>(null);
    
        useEffect(() => {
            apiFunction(params)
                .then(({ data }: AxiosResponse) => {
                    setData(data);
                    setIsLoading(false);
                    if (callback) {
                        callback(data);
                    }
                })
                .catch(() => {
                    setError('Something went wrong');
                    setIsLoading(false);
                });
        }, []); //apiFunction, params, callback]
    
        return [isLoading, data, error];
    };
    
    export default useApi;
    
    getMovie对应一个解决web请求的函数
    import axios from "axios";
    type getMovieParams = { _id: string };
    const BASE_URL = "https://jsonplaceholder.typicode.com/todos/";
    const getMovie = (params: getMovieParams): Promise<unknown> => {
      if (params) {
        const { _id } = params;
        if (_id) {
          const url = `${BASE_URL}/${_id}`;
          return axios.get(url);
        }
      }
      throw new Error("Must provide a query");
    };
    
    export default getMovie;
    
    调用此钩子(Hook)的代码如下所示:
    import "./styles.css";
    import useApi from "./useApi";
    import getMovie from "./api";
    interface Movie {
      userId: number;
      id: number;
      title: string;
      completed: boolean;
    }
    
    export default function App() {
      const idMovie = { _id: "3" };
      // callback function
      const someAction = (data: unknown) => {
        // do something
        return data;
      };
    
      const [isLoading, data, error] = useApi(getMovie, idMovie, someAction);
    
      const dataResponse = error ? [] : data; //type Movie
      console.log(dataResponse);
      if (isLoading) {
        return <div>Loading...</div>;
      }
    
      return (
        <div>
          {error && <div>{error}</div>}
          -- Get Data Movie 1--
          <p>{dataResponse.title}</p>
        </div>
      );
    }
    
    我在这一行遇到打字错误:
    <p>{dataResponse.title}</p>
    
    这是因为:
    const dataResponse = error ? [] : data; 
    
    data类型为 unknown ,这是因为它可以是任何类型的 data ,但我想在这种情况下指定数据类型为 ' Movie ',想法是在另一个组件中重用这个钩子(Hook),并且能够说出当这个钩子(Hook)返回时将获得的数据类型data .
    这是我的实时代码:
    https://codesandbox.io/s/vigilant-swartz-iozn4
    创建这个问题的原因是请求您的帮助解决用红线标记的 typescript 问题。 (文件 app.tsx)
    enter image description here
    如何解决?谢谢

    最佳答案

    可以使用 generics捕获与传递给函数的参数相关的类型。例如,在您拥有的屏幕截图中,关于 params 的 TS 投诉,我们可以声明一个泛型来捕获 params 类型

    function useApi<Params>(
      apiFunction: (params: Params) => AxiosPromise,
      params: Params,
      callback: (data: unknown) => void
    )
    
    有了这个,我们的第二个钩子(Hook)参数将被输入为 apiFunction 的任何类型。在其 arg 中要求。
    我们做同样的事情来输入我们返回到回调的数据
    function useApi<Params, Return>(
      apiFunction: (params: Params) => Promise<AxiosResponse<Return>>,
      params: Params,
      callback: (data: Return) => void
    )
    
    我得到了 apiFunction 的返回类型通过检查 axios.get 的类型称呼get<T = any, R = AxiosResponse<T>>(url: string, config?: AxiosRequestConfig): Promise<R>;如您所见,最后它返回一个 Promise<AxiosResponse<T>> .我们拦截了 T使用我们的通用类型并将其命名 Return现在我们也可以在钩子(Hook)的返回类型和主体中使用这些类型
    ): [boolean, Return | null, null | string] {
      const [data, setData] = useState<Return | null>(null);
      const [isLoading, setIsLoading] = useState(true);
      const [error, setError] = useState<null | string>(null);
    
      useEffect(() => {
        apiFunction(params)
          .then(({ data }) => {
            setData(data);
            setIsLoading(false);
            if (callback) {
              callback(data);
            }
          })
          .catch(() => {
            setError("Something went wrong");
            setIsLoading(false);
          });
      }, []); //apiFunction, params, callback]
    
      return [isLoading, data, error];
    }
    
    由于您的电影模型特定于 getMovie 调用,您可以将该界面移到那里并输入 axios.get称呼
    interface Movie {
      userId: number;
      id: number;
      title: string;
      completed: boolean;
    }
    
    const getMovie = (params: getMovieParams) => {
      if (params) {
        const { _id } = params;
        if (_id) {
          const url = `${BASE_URL}/${_id}`;
          return axios.get<Movie>(url);
        }
      }
      throw new Error("Must provide a query");
    };
    
    通过所有这些添加,当您使用钩子(Hook)时,您会在代码中观察到一些警告,这将迫使您考虑所有可能的值来实现渲染,我像这样重写了它
      ...
      const [isLoading, dataResponse, error] = useApi(
        getMovie,
        idMovie,
        someAction
      );
    
      if (isLoading) {
        return <div>Loading...</div>;
      }
    
      if (error) return <div>error</div>;
    
      return <div>{dataResponse?.title}</div>;
      ...
    
    https://codesandbox.io/s/generic-hook-arg-types-s8vtt

    关于reactjs - 如何使变量的类型为未知或 'Movie' 分配?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69384239/

    相关文章:

    reactjs - react native : Can react native find out the exact absolute position for each device?

    typescript - "name ' 大小 ' does not exist in the current scope"即使我 've referenced it and it isn' t 突出显示?

    angular - 正确使用 Angular TypeScript 构造函数 - 无法解析所有参数

    angular - 如何导入 json 文件以在 angular-cli npm test 中可用

    javascript - 为什么 ReactJS 将代码与 HTML 混合的方式是更好的设计?

    reactjs - Material-ui:通过事件悬停打开菜单

    javascript - 用于分页的 RXJS while 循环

    angular - ionic 3 中没有 CallNumber 的提供者

    reactjs - 使用 NextJS 减少 JS 执行时间

    reactjs - create-react-app 何时混淆或缩小代码?