My App

在挂载时获取

在挂载时获取

在上一课中,我们看到如何在事件发生时(例如表单提交)发起网络请求。但如果我们需要获取数据以填充初始视图呢?

例如,假设我们正在构建一个天气应用程序。我们想向用户显示他们所在地区的当前温度:

我们想在组件挂载时立即显示温度。

这是一个出乎意料的棘手问题。看起来似乎只是一个小差别,即在挂载时获取而不是在事件中获取,但这会引发一系列复杂的问题。

首先,人体工程学比较棘手。为了在挂载时获取,我们通常会使用 useEffect 钩子,但是在 effect 中使用 async/await 有一些注意事项(将在即将到来的课程中讲解)。

此外,如果我们想以一种稳健、适合生产环境的方式解决这个问题,我们需要关注各种各样的顾虑,包括:

  • 缓存响应,以便可以被应用程序中的多个组件重用。
  • 重新验证数据,以确保它不会变得过于陈旧。

这就是一个我们可以迷失数天的兔子洞。😬

因此,在社区中使用工具来帮助处理这些事情已成为标准。React 文档*,例如,建议使用像 React Query 或 SWR 这样的包。事实上,在这个课程平台上,我使用 SWR 来解决所有这些难题!

swr

让我们看看它是如何工作的。

SWR 简介

这是一个 MVP实现。随意去试探和挑剔它。我们将在下面讨论它是如何工作的。

import React from 'react';
import useSWR from 'swr';

const ENDPOINT =
  'https://jor-test-api.vercel.app/api/get-temperature';

async function fetcher(endpoint) {
  const response = await fetch(endpoint);
  const json = await response.json();
  
  return json;
}

function App() {
  const { data, error } = useSWR(ENDPOINT, fetcher);
  
  console.log(data, error);
  
  return (
    <p>
      Current temperature:
      {typeof data?.temperature === 'number' && (
        <span className="temperature">
          {data.temperature}°C
        </span>
      )}
    </p>
  );
}

export default App;

那是什么语法?

此代码使用可选链操作符 ( ?. )。您可以在我的“操作符查找”工具中了解更多信息。

让我们深入研究这段代码:

加载和错误状态

我们上面的 MVP 不包括加载或错误状态。让我们看看如何使用 SWR 实现它们。

加载中(Loading)

除了提供一个 data 值, useSWR 钩子还告诉我们请求是否正在加载。我们可以提取 isLoading 键:

const { data, isLoading } = useSWR(ENDPOINT, fetcher);

isLoading 是一个布尔值。初始值为 true ,在获取请求完成后会切换为 false 。

我们可以使用该值有条件地渲染一个加载 UI,如下所示:

function App() {
  const { data, isLoading } = useSWR(ENDPOINT, fetcher);
 
  if (isLoading) {
    return (
      <p>Loading…</p>
    );
  }
 
  return (
    <p>
      Current temperature:
      {typeof data.temperature === "number" && (
        <span className="temperature">{data.temperature}°C</span>
      )}
    </p>
  );
}

错误(Error)

为了模拟一个错误,我们可以向 ENDPOINT 添加一个查询参数:

const ENDPOINT =
  "https://jor-test-api.vercel.app/api/get-temperature?simulatedError=true";

这将导致服务器返回 500 状态码👀,而不是 200。它还将返回以下 JSON:

{
  "error": "This request returns an error, because the “simulatedError” query parameter was specified."
}

然而,对于 SWR 来说,这两者都不足以将其标记为错误。

记住:我们管理网络请求!我们的 fetcher 函数负责检索数据,并将其传递给 SWR。如果我们希望这被视为错误,我们需要抛出它:

async function fetcher(endpoint) {
  const response = await fetch(endpoint);
  const json = await response.json();
 
  if (!json.ok) {
    throw json;
  }
 
  return json;
}

完成此更改后, data 将未定义, error 将是我们从服务器返回的对象。

扔出一个object?!

在 JavaScript 中,通常会抛出一个 Error ,如下所示:

if (!json.ok) {
  throw new Error("Some sort of error message");
}

然而,在使用 SWR 时,我更喜欢抛出 JSON 对象。

if (!json.ok) {
  throw json;
}

这同样有效,这意味着 error 将是一个对象,而不是一个 Error 实例。这更容易处理,因为我可以访问与错误相关的数据。

这是最终实现,包括加载和错误状态:

import React from 'react';
import useSWR from 'swr';

// Remove "?simulatedError=true" to see the success state:
const ENDPOINT =
  'https://jor-test-api.vercel.app/api/get-temperature?simulatedError=true';

async function fetcher(endpoint) {
  const response = await fetch(endpoint);
  const json = await response.json();

  if (!json.ok) {
    throw json;
  }

  return json;
}

function App() {
  const { data, isLoading, error } = useSWR(ENDPOINT, fetcher);

  if (isLoading) {
    return <p>Loading…</p>;
  }

  if (error) {
    return <p>Something's gone wrong</p>;
  }

  return (
    <p>
      Current temperature:
      {typeof data?.temperature === 'number' && (
        <span className="temperature">
          {data.temperature}°C
        </span>
      )}
    </p>
  );
}

export default App;

On this page