1. 数据缓存策略设计
- 选择缓存技术:在React PWA中,可使用
localStorage
、IndexedDB
或Cache API
。IndexedDB
适合大量结构化数据存储,Cache API
主要用于缓存网络请求响应,localStorage
适合简单少量数据存储。对于API数据,IndexedDB
通常是较好选择,因为它能存储复杂数据结构且容量较大。
- 缓存时机:
- 首次加载:在组件挂载时,先检查缓存中是否有对应数据。如果有,使用缓存数据渲染组件,同时发起网络请求获取最新数据。
- 更新操作:当组件接收到新的props或状态变化触发重新渲染时,同样先使用缓存数据,然后触发更新数据的网络请求。
2. 离线状态处理
- 优先读取缓存:在
componentDidMount
或useEffect
钩子函数中,首先尝试从缓存(如IndexedDB
)中读取数据。如果成功读取到数据,立即使用这些数据渲染组件,以保证用户能在离线状态下看到内容。
import React, { useEffect, useState } from 'react';
import { readFromCache } from './cacheUtils';
const MyComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const cachedData = await readFromCache('apiDataKey');
if (cachedData) {
setData(cachedData);
}
// 这里同时发起网络请求更新数据(见在线状态处理部分)
};
fetchData();
}, []);
return (
<div>
{data && <p>{JSON.stringify(data)}</p>}
</div>
);
};
export default MyComponent;
3. 在线状态处理
- 后台更新:在获取到缓存数据并渲染组件后,发起网络请求获取最新数据。一旦网络请求成功,将新数据存储到缓存中,并更新组件状态以重新渲染显示最新数据。
import React, { useEffect, useState } from 'react';
import { readFromCache, writeToCache } from './cacheUtils';
import axios from 'axios';
const MyComponent = () => {
const [data, setData] = useState(null);
useEffect(() => {
const fetchData = async () => {
const cachedData = await readFromCache('apiDataKey');
if (cachedData) {
setData(cachedData);
}
try {
const response = await axios.get('/api/data');
await writeToCache('apiDataKey', response.data);
setData(response.data);
} catch (error) {
console.error('Error fetching data:', error);
}
};
fetchData();
}, []);
return (
<div>
{data && <p>{JSON.stringify(data)}</p>}
</div>
);
};
export default MyComponent;
4. 缓存数据版本控制
- 添加版本标识:在缓存数据时,为数据添加版本号。可以在缓存对象中增加一个
version
字段,每次数据更新时,版本号递增。
const writeToCache = async (key, data) => {
const cache = await window.indexedDB.open('myCacheDB', 1);
cache.onupgradeneeded = (event) => {
const db = event.target.result;
const objectStore = db.createObjectStore('dataStore', { keyPath: 'id' });
};
const tx = cache.transaction(['dataStore'], 'readwrite');
const store = tx.objectStore('dataStore');
const existingData = await store.get(key);
const newData = {
id: key,
data,
version: existingData? existingData.version + 1 : 1
};
store.put(newData);
};
- 版本检查:在读取缓存数据时,检查版本号。如果版本号低于预期(例如,服务端告知了最新版本号),则发起网络请求更新数据。
5. 缓存数据一致性
- 数据更新策略:为保证一致性,当数据更新时,不仅要更新缓存中的数据,还要确保所有依赖该数据的组件都能及时获取到新数据。可以使用发布 - 订阅模式或Redux等状态管理工具。
- 发布 - 订阅模式:当数据更新时,发布者通知所有订阅该数据的组件进行更新。
- Redux:将缓存数据存储在Redux store中,当数据更新时,通过action和reducer更新store,所有订阅该store状态的组件会自动重新渲染。
- 避免并发冲突:在多个组件同时更新缓存数据时,可能会发生冲突。可以通过使用事务(如
IndexedDB
中的事务)来确保数据操作的原子性,避免并发冲突。例如,在更新数据时,使用readwrite
事务,确保在同一时间只有一个组件能修改缓存数据。