用Typescript编写自定义React Hooks

367 阅读3分钟

用Typescript编写自定义React钩子和用普通的JavaScript编写钩子并没有什么不同。在这篇文章中,我们将回顾用Typescript编写自己的React钩子的一些基础知识和 "问题"。

例子 一个简单的useFetch钩子

为了演示如何编写我们的钩子,我们将编写一个钩子,做一些网络应用中非常普遍的事情:获取数据。我们的钩子将被称为useFetch

重要的是,我们在这里只是进行基础的学习,所以这将是一个非常原始的钩子。如果你想在生产中真正使用useFetch 钩子,我建议你在谷歌上搜索一个现有的钩子,它有更多的功能和口哨。

发出GET请求

要用我们的钩子发出一个获取请求,我们知道我们需要一个URL,并且我们需要返回一些获取的数据。因此,我们的useFetch 钩子,将有一个url 参数,这个参数是一个string ,并将使用useState 钩子内置的反应存储我们获取的数据。

import { useState } from 'react';

function useFetch(url: string) {
  const [data, setData] = useState(null);

  // Fetch the data here

  return data;
}

现在是有趣的部分:让我们来获取和设置我们的数据吧我们可以简单地使用我们窗口的fetch 方法和setData 到响应。

import { useState } from 'react';

function useFetch(url: string) {
  const [data, setData] = useState(null);

  // Fetch the data here
  fetch(url)
    .then((res) => {
      return res.json();
    })
    .then((res) => {
      setData(res);
    });

  return data;
}

让我们通过在一个应用程序中使用我们的钩子来看看这个动作。

import { useFetch } from './useFetch';

function App() {
  const data = useFetch('https://api.github.com/users/nas5w');

  return data ? <>{JSON.stringify(data)}</> : <>Loading...</>;
}

export default App;

这就成功了。在我们的获取过程中,我们会看到一个Loading... ,然后我们的字符串化的github数据会显示。

但这还不够好:我们的应用程序认为data 的类型是null ,因为那是我们在钩子中明确给我们的有状态的data 变量的唯一类型。

不够好!我们需要键入返回值

为了让自己能够从我们的useFetch 钩子中键入返回值,我们可以使用Typescript泛型来给我们的钩子传递一个类型。让我们看看这将是什么样子。

import { useState } from 'react';

function useFetch<D>(url: string) {
  const [data, setData] = useState<D | null>(null);

  // Fetch the data here
  fetch(url)
    .then((res) => {
      return res.json();
    })
    .then((res) => {
      setData(res);
    });

  return data;
}

所以现在我们已经告诉我们的钩子必须提供一个类型,D ,而data 的类型将是Dnull 。我们现在可以重新审视我们的App.tsx 文件并调整我们如何使用这个钩子。

在这个练习中,我已经创建了一个基本的GithubResponse 类型。它可能不是100%正确的,但对于这个演示来说已经足够好了

import { useFetch } from './useFetch';

function App() {
  const data = useFetch<GithubResponse>('https://api.github.com/users/nas5w');

  return data ? (
    <>
      Name: {data.login}
      <br />
      Followers: {data.followers}
    </>
  ) : (
    <>Loading...</>
  );
}

export default App;

type GithubResponse = {
  login: string;
  id: number;
  node_id: string;
  avatar_url: string;
  gravatar_id: string;
  url: string;
  html_url: string;
  followers_url: string;
  following_url: string;
  gists_url: string;
  starred_url: string;
  subscriptions_url: string;
  organizations_url: string;
  repos_url: string;
  events_url: string;
  received_events_url: string;
  type: string;
  site_admin: boolean;
  name: string;
  company: string | null;
  blog: string | null;
  location: string | null;
  email: string | null;
  hireable: string | null;
  bio: string;
  twitter_username: string | null;
  public_repos: number;
  public_gists: number;
  followers: number;
  following: number;
  created_at: string;
  updated_at: string;
};

正如我们所看到的,我们的代码被编译了,这意味着Typescript理解我们返回的对象类型!

image.png

TL;DR:泛型使你的钩子发挥作用

TL;DR在这里是,Typescript泛型是让你的React Hooks在Typescript中工作的关键!