自以为是的 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>
);
}
下面是一个例子,我们获取了一个用户,并翻转一个布尔值来表示加载已完成。这没问题……但我们并不知道我们的handleGetUser
函数是否成功获取了用户。
user
null
如果获取调用失败,仍然可能。
我们可以向我们的函数添加一个try / catch
块handleGetUser
,就像这样。
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>
);
}
我们现在正在跟踪错误消息,但仍然没有真正解决将isLoading
设置为 false 后会发生什么的问题。我们需要做一些检查来弄清楚。
// loading
isLoading === true
// success
isLoading === false && user !== null && !error
// error
isLoading === false && !user && error !== ''
即使有几种不同的状态,我们也要做太多的思考。
更好的方法 - 使用枚举
枚举(enumeration 的缩写)允许我们定义一组命名常量。这些常量可用于创建一组不同的用例。
export enum UserStatus {
LOADING = "loading",
SUCCESS = "success",
ERROR = "error",
}
我们可以定义不同的“状态”,并像这样使用它们:
*请注意,我在这里使用了三个单独的 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>
);
}
这更容易推理,并且允许我们稍后根据需要添加更多状态。👍
总结
这是我的“Opinionated React”系列的第六篇文章。一如既往,我乐于接受反馈。
如果您想要更多类似的内容,或者有一些疑问,您可以在 Twitter 上找到我。
下次再见。
文章来源:https://dev.to/farazamiruddin/opinionated-react-use-status-enums-instead-of-booleans-3ha5