React:编写自定义 API 钩子
让我们编写一个方便的自定义反应钩子来处理我们一次又一次编写的常见 API 逻辑。
介绍
离开 React 几年后,我正在重新学习最佳实践。这意味着:Hooks
我们在应用程序中发现的一个非常常见的流程是从 API 加载数据并显示它。
它通常看起来有点像这样:
这很容易导致组件变得非常混乱。让我们利用新学到的 Hooks 知识来解决这个问题。
设计钩子
根据上面描述的流程,定义我们想要钩子提供的数据非常容易。它将返回:
- 响应数据
- 正在加载标志
- 错误(成功则为空)
- 重试方法
鉴于我仍然欣赏将请求代码委托给服务类,我的想法是让钩子调用服务。
导致以下用法:
const [ user, isLoading, error, retry ] = useAPI('loadUserById', 56);
准备 API 服务
让我们使用一个小服务类,我们可以将所有漂亮的 ajax 代码放在其中。
class APIService {
async loadUsers() {
// ... ajax magic
}
async loadUserById(id) {
// ... ajax magic
}
}
export default new APIService();
写钩子
我们的目标只是结合标准的反应钩子来创建所有必需的字段。
国家
React 已经为我们提供了useState钩子来创建和更新状态属性。
让我们生成我们的字段:
function useAPI(method, ...params) {
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, onError] = useState(null);
}
调用服务
这里起作用的 React hook 是useEffect,我们可以在其中运行异步代码。
useEffect(() => {
// ... async code
}, []);
但是,我们决定让钩子返回一个retry
方法。因此,让我们将异步代码移到它自己的函数中。
const fetchData = async () => {
// ... async code
}
useEffect(() => { fetchData() }, []);
现在让我们根据钩子的参数调用正确的服务方法
const fetchData = async () => {
// Clear previous errors
onError(null);
try {
// Start loading indicator
setIsLoading(true);
// Fetch and set data
setData(await APIService[method](...params));
} catch (e) {
// Set the error message in case of failure
setError(e);
} finally {
// Clear loading indicator
setIsLoading(false);
}
};
useEffect(() => { fetchData() }, []);
结果
瞧!我们的鱼钩已经准备好了。
function useAPI(method, ...params) {
// ---- State
const [data, setData] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState(null);
// ---- API
const fetchData = async () => {
onError(null);
try {
setIsLoading(true);
setData(await APIService[method](...params));
} catch (e) {
setError(e);
} finally {
setIsLoading(false);
}
};
useEffect(() => { fetchData() }, []);
return [ data, isLoading, error, fetchData ];
}
在组件中的使用
让我们写一个小例子来说明如何在组件中使用它
function HomeScreen() {
const [ users, isLoading, error, retry ] = useAPI('loadUsers');
// --- Display error
if (error) {
return <ErrorPopup msg={error.message} retryCb={retry}></ErrorPopup>
}
// --- Template
return (
<View>
<LoadingSpinner loading={isLoading}></LoadingSpinner>
{
(users && users.length > 0) &&
<UserList users={users}></UserList>
}
</View>
);
}
结论
有很多方法可以避免在整个应用程序中重写通用代码。
过去,我经常将其中一些委托给Store
,或者用来Mixins
创建所有可立即使用的逻辑的组件。
自定义钩子给我们带来了全新的感受,并开辟了解决问题的新策略。
很高兴见证实践的演变。
干杯,
帕特里克
文章来源:https://dev.to/patrixr/react-writing-a-custom-api-hook-l16