自以为是的 React - 使用状态枚举而不是布尔值简介为什么这是一个坏主意 - 一个例子更好的方法 - 使用枚举总结

2025-06-05

自以为是的 React - 使用状态枚举而不是布尔值

简介

为什么

为什么这是个坏主意——一个例子

更好的方法 - 使用枚举

总结

简介

我使用 React 已经四年多了。在此期间,我对应用程序应该是什么样子形成了自己的看法。这是本系列的第六部分。

为什么

当我开始编写 React 时,我经常使用isLoading布尔值来指示我正在异步加载一些数据。

对于一个简单的例子来说这很好,但据我所知它的扩展性并不好。

为什么这是个坏主意——一个例子

import * as React from "react";
import { getUserById } from "./services/user-service";
import { User } from "./types/user";

export function App() {
  const [user, setUser] = React.useState(null);
  const [isLoading, setIsLoading] = React.useState(true);

  React.useEffect(() => {
    const handleGetUser = async (id: string) => {
      const user = await getUserById(id);
      setUser(user);
      setIsLoading(false);
    };

    handleGetUser("1");
  }, []);

  return (
    <div>
      {isLoading && <p>Loading...</p>}
      {!isLoading && user && <UserProfile user={user} />}
    </div>
  );
}

function UserProfile({ user }: { user: User }) {
  return (
    <div>
      <p>{user.displayName}</p>
      <p>{user.email}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

下面是一个例子,我们获取了一个用户,并翻转一个布尔值来表示加载已完成。这没问题……但我们并不知道我们的handleGetUser函数是否成功获取了用户。

usernull如果获取调用失败,仍然可能。

我们可以向我们的函数添加一个try / catchhandleGetUser,就像这样。

import * as React from "react";
import { getUserById } from "./services/user-service";
import { User } from "./types/user";

export function App() {
  const [user, setUser] = React.useState(null);
  const [isLoading, setIsLoading] = React.useState(true);
  const [errorMessage, setErrorMessage] = React.useState('');

  React.useEffect(() => {
    const handleGetUser = async (id: string) => {
      try {
        // Clearing the error message.
        setErrorMessage('');
        const user = await getUserById(id);
        setUser(user);
      } catch (error) {
        setErrorMessage(error.message)
      }
      // Set isLoading to false regardless of 
      // if the call succeeds or fails.
      setIsLoading(false);
    };
    handleGetUser("1");
  }, []);

  return (
    <div>
      {isLoading && <p>Loading...</p>}
      {!isLoading && user && <UserProfile user={user} />}
    </div>
  );
}

function UserProfile({ user }: { user: User }) {
  return (
    <div>
      <p>{user.displayName}</p>
      <p>{user.email}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

我们现在正在跟踪错误消息,但仍然没有真正解决将isLoading设置为 false 后会发生什么的问题。我们需要做一些检查来弄清楚。

// loading
isLoading === true

// success
isLoading === false && user !== null && !error

// error
isLoading === false && !user && error !== ''
Enter fullscreen mode Exit fullscreen mode

即使有几种不同的状态,我们也要做太多的思考。

更好的方法 - 使用枚举

枚举(enumeration 的缩写)允许我们定义一组命名常量。这些常量可用于创建一组不同的用例。

export enum UserStatus {
  LOADING = "loading",
  SUCCESS = "success",
  ERROR = "error",
}
Enter fullscreen mode Exit fullscreen mode

我们可以定义不同的“状态”,并像这样使用它们:

*请注意,我在这里使用了三个单独的 useState 调用,这并非我实际会做的事情。这只是为了学习。如果您想了解我如何管理状态,可以查看这篇文章。

import * as React from "react";
import { getUserById } from "./services/user-service";
import { User } from "./types/user";
import { UserStatus } from "./constants/user-status";

export function App() {
  const [user, setUser] = React.useState<User | null>(null);
  const [status, setStatus] = React.useState<UserStatus>(UserStatus.LOADING);
  const [errorMessage, setErrorMessage] = React.useState<string>('');

  React.useEffect(() => {
    const handleGetUser = async (id: string) => {
      try {
        // Clearing the error message.
        setErrorMessage('');
        const user = await getUserById(id);
        setUser(user);
        setStatus(UserStatus.SUCCESS);
      } catch (error) {
        setErrorMessage(error.message)
        setStatus(UserStatus.ERROR);
      }
    };
    handleGetUser("1");
  }, []);

  if (status === UserStatus.ERROR) {
    return <div><p>Oops, something went wrong.</p></div>
  }

  return (
    <div>
      {status === UserStatus.LOADING && <p>Loading...</p>}
      {status === UserStatus.SUCCESS && <UserProfile user={user} />}
    </div>
  );
}

function UserProfile({ user }: { user: User }) {
  return (
    <div>
      <p>{user.displayName}</p>
      <p>{user.email}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

这更容易推理,并且允许我们稍后根据需要添加更多状态。👍

总结

这是我的“Opinionated React”系列的第六篇文章。一如既往,我乐于接受反馈。

如果您想要更多类似的内容,或者有一些疑问,您可以在 Twitter 上找到我。

下次再见。

文章来源:https://dev.to/farazamiruddin/opinionated-react-use-status-enums-instead-of-booleans-3ha5
PREV
如何在 Ubuntu 上更新 Docker 和 Docker Compose
NEXT
Opinionated React: Use Context for Shared State Intro My Pattern for React Context Why Use Cases - Important! Inspiration Example Wrapping Up