在 React 项目中,将业务逻辑与组件逻辑分离,能使代码更加模块化、可维护且易于复用。自定义 Hooks 是实现这一目标的有效方式。本文将详细介绍如何使用自定义 Hooks 封装 service 逻辑,并通过具体实例展示其实际应用。
自定义 Hooks 封装 Service 的好处
- 状态管理和副作用处理:自定义 Hooks 可以处理组件的状态和副作用逻辑,使得组件代码更加简洁。
- 复用性:将常用的业务逻辑封装在自定义 Hooks 中,可以在多个组件中复用这些逻辑。
- 解耦逻辑:通过自定义 Hooks,将数据获取、同步等业务逻辑从 UI 逻辑中解耦出来,使得代码结构更加清晰。
具体实现步骤
Step 1: 封装 API 调用逻辑
将 API 调用逻辑封装在一个独立的模块中,集中管理与服务器交互的逻辑。
// apiService.js
const BASE_URL = 'https://api.example.com';
export async function fetchData() {
const response = await fetch(`${BASE_URL}/data`);
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
}
Step 2: 封装 SQLite 操作逻辑
将 SQLite 的插入和查询逻辑封装在一个模块中,集中管理与数据库交互的逻辑。
// sqliteService.js
import * as SQLite from 'expo-sqlite';
const db = SQLite.openDatabase('app.db');
export function insertData(data) {
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql(
'INSERT INTO data (id, value) VALUES (?, ?)',
[data.id, data.value],
(_, result) => resolve(result),
(_, error) => reject(error)
);
});
});
}
export function selectData() {
return new Promise((resolve, reject) => {
db.transaction(tx => {
tx.executeSql(
'SELECT * FROM data',
[],
(_, result) => resolve(result.rows._array),
(_, error) => reject(error)
);
});
});
}
Step 3: 创建同步逻辑的 Service
创建一个 service,将服务器的数据同步到 SQLite 中。
// syncService.js
import { fetchData } from './apiService';
import { insertData } from './sqliteService';
export async function syncData() {
try {
const data = await fetchData();
await Promise.all(data.map(item => insertData(item)));
console.log('Data synced successfully');
} catch (error) {
console.error('Failed to sync data:', error);
}
}
Step 4: 创建自定义 Hook 封装业务逻辑
为了在组件中使用同步逻辑,我们创建一个自定义 Hook,支持定时任务和手动触发同步逻辑。
// useSync.js
import { useState, useEffect, useCallback } from 'react';
import { syncData } from './syncService';
function useSync(interval) {
const [syncing, setSyncing] = useState(false);
const [error, setError] = useState(null);
const startSync = useCallback(async () => {
setSyncing(true);
setError(null);
try {
await syncData();
} catch (err) {
setError(err);
} finally {
setSyncing(false);
}
}, []);
useEffect(() => {
// Initial sync when the component mounts
startSync();
if (interval) {
// Set up the interval for periodic sync
const intervalId = setInterval(startSync, interval);
// Clean up the interval on unmount
return () => clearInterval(intervalId);
}
}, [startSync, interval]);
return { syncing, error, startSync };
}
export default useSync;
Step 5: 在组件中使用自定义 Hook
在组件中使用这个自定义 Hook,可以在组件挂载时和定时任务触发同步逻辑,同时也可以手动触发同步逻辑。
// SyncComponent.js
import React from 'react';
import useSync from './useSync';
function SyncComponent() {
const { syncing, error, startSync } = useSync(60000); // 60秒间隔
return (
<div>
{syncing && <div>Syncing data...</div>}
{error && <div>Error syncing data: {error.message}</div>}
<button onClick={startSync}>Sync Now</button>
{/* 渲染你的列表 */}
</div>
);
}
export default SyncComponent;
总结
通过以上步骤,我们将复杂的业务逻辑封装在 service 中,并通过自定义 Hooks 将这些业务逻辑引入到组件中。这种方式不仅提高了代码的可维护性,还使得业务逻辑更加清晰,组件更加专注于 UI 渲染。
使用自定义 Hooks 封装 service,可以使状态管理和副作用处理更加简洁和集中,同时提高代码的复用性和模块化程度。这种设计模式灵活且可扩展,可以根据实际需求调整同步的触发条件。