【HarmonyOS】RN of HarmonyOS实战开发项目+TanStack缓存策略

在这里插入图片描述
欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

摘要

本文深入探讨React Native应用中TanStack Query(原React Query)在OpenHarmony 6.0.0平台上的缓存策略实现与性能优化。文章系统分析TanStack Query核心机制、缓存生命周期管理、动态策略调整以及持久化方案,通过架构图、状态图和参数对比表详细阐述staleTime、cacheTime等关键配置项的应用场景。所有内容基于React Native 0.72.5和TypeScript 4.8.4技术栈,已在AtomGitDemos项目中完成OpenHarmony 6.0.0 (API 20)设备验证。读者将掌握在开源鸿蒙环境下设计高效缓存策略的实战技能。


一、TanStack Query缓存架构

1.1 核心架构解析

┌─────────────────────────────────────────────────────────────────────────┐
│                         QueryClient (查询客户端)                        │
│  ┌─────────────────────────────────────────────────────────────────────┐ │
│  │                   QueryCache (查询缓存管理器)                       │ │
│  │  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐          │ │
│  │  │   Query 1    │  │   Query 2    │  │   Query N    │          │ │
│  │  │  queryKey:   │  │  queryKey:   │  │  queryKey:   │          │ │
│  │  │  ['users']   │  │  ['posts']   │  │  ['todos']   │          │ │
│  │  │  ┌────────┐  │  │  ┌────────┐  │  │  ┌────────┐  │          │ │
│  │  │  │ Query  │  │  │  │ Query  │  │  │  │ Query  │  │          │ │
│  │  │  │ State  │  │  │  │ State  │  │  │  │ State  │  │          │ │
│  │  │  └────────┘  │  │  └────────┘  │  │  └────────┘  │          │ │
│  │  └──────────────┘  └──────────────┘  └──────────────┘          │ │
│  └─────────────────────────────────────────────────────────────────────┘ │
│  ┌─────────────────────────────────────────────────────────────────────┐ │
│  │                MutationCache (变更缓存管理器)                        │ │
│  │  ┌──────────────┐  ┌──────────────┐                               │ │
│  │  │  Mutation 1  │  │  Mutation N  │                               │ │
│  │  └──────────────┘  └──────────────┘                               │ │
│  └─────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
                              │
                              ▼
                    ┌─────────────────┐
                    │ QueryObserver  │ ← React组件订阅
                    └─────────────────┘

1.2 缓存状态生命周期

首次请求

请求成功

请求失败

数据新鲜

超过staleTime

后台重新获取

获取成功

获取失败(保持stale状态)

无组件订阅

超过cacheTime被GC

无组件订阅且过期

Loading

Success

Error

Fresh

Stale

Fetching

Inactive

staleTime: 数据被视为新鲜的时间
默认0ms,OpenHarmony推荐30000ms

cacheTime: 缓存保留时间
默认5分钟,OpenHarmony推荐2分钟

1.3 核心配置参数详解

参数 类型 默认值 OpenHarmony推荐值 说明
staleTime number 0 30000 (30秒) 数据被视为fresh的时间
cacheTime number 300000 (5分) 120000 (2分) 缓存保留时间
refetchOnMount boolean|function true false 组件挂载时是否重新获取
refetchOnWindowFocus boolean|function true false 应用回到前台时刷新
refetchOnReconnect boolean|function true true 网络重连时刷新
retry number|boolean|function 3 2 失败重试次数
retryDelay number|function 1000 2000 重试延迟(毫秒)

二、OpenHarmony平台缓存适配

2.1 平台差异分析

特性 iOS/Android OpenHarmony 6.0.0 适配策略
后台任务限制 较宽松 严格限制 refetchOnWindowFocus: false
内存回收策略 按需回收 积极回收 减少cacheTime
网络状态API NetInfo库 @ohos.net.connection 使用原生API
应用生命周期 前台/后台 前台/后台/挂起 监听挂起状态
持久化存储 AsyncStorage Preferences API 统一抽象层

2.2 网络状态感知缓存

import connection from '@ohos.net.connection';

type NetworkType = 'wifi' | 'cellular_4g' | 'cellular_3g' | 'none';

interface CacheStrategy {
  staleTime: number;
  cacheTime: number;
  refetchOnWindowFocus: boolean;
  refetchOnReconnect: boolean;
  retry: number;
  retryDelay: number;
}

class NetworkAwareCacheStrategy {
  private currentNetwork: NetworkType = 'none';

  async init() {
    await this.updateNetworkState();

    // 监听网络状态变化
    connection.on('netAvailable', this.handleNetworkChange);
    connection.on('netLost', this.handleNetworkLost);
  }

  private async updateNetworkState() {
    try {
      const netHandle = await connection.getDefaultNet();
      if (!netHandle) {
        this.currentNetwork = 'none';
        return;
      }

      const properties = await netHandle.getConnectionProperties();

      switch (properties.bearerType) {
        case connection.NetBearType.BEARER_WIFI:
          this.currentNetwork = 'wifi';
          break;
        case connection.NetBearType.BEARER_CELLULAR:
          // 根据信号强度判断4G/3G
          this.currentNetwork = 'cellular_4g';
          break;
        default:
          this.currentNetwork = 'none';
      }
    } catch {
      this.currentNetwork = 'none';
    }
  }

  private handleNetworkChange = async () => {
    await this.updateNetworkState();
  };

  private handleNetworkLost = () => {
    this.currentNetwork = 'none';
  };

  getStrategy(): CacheStrategy {
    const strategies: Record<NetworkType, CacheStrategy> = {
      wifi: {
        staleTime: 60000,        // WiFi下60秒
        cacheTime: 300000,       // 保留5分钟
        refetchOnWindowFocus: false,
        refetchOnReconnect: true,
        retry: 2,
        retryDelay: 1000,
      },
      cellular_4g: {
        staleTime: 30000,        // 4G下30秒
        cacheTime: 120000,       // 保留2分钟
        refetchOnWindowFocus: false,
        refetchOnReconnect: true,
        retry: 1,
        retryDelay: 2000,
      },
      cellular_3g: {
        staleTime: 15000,        // 3G下15秒
        cacheTime: 60000,        // 保留1分钟
        refetchOnWindowFocus: false,
        refetchOnReconnect: false,
        retry: 1,
        retryDelay: 3000,
      },
      none: {
        staleTime: Infinity,    // 离线时永不过期
        cacheTime: 600000,       // 保留10分钟
        refetchOnWindowFocus: false,
        refetchOnReconnect: true,
        retry: 0,
        retryDelay: 0,
      },
    };

    return strategies[this.currentNetwork];
  }

  getCurrentNetwork(): NetworkType {
    return this.currentNetwork;
  }
}

// 使用示例
const cacheStrategy = new NetworkAwareCacheStrategy();
await cacheStrategy.init();

const strategy = cacheStrategy.getStrategy();

// 应用策略到QueryClient
const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      staleTime: strategy.staleTime,
      cacheTime: strategy.cacheTime,
      refetchOnWindowFocus: strategy.refetchOnWindowFocus,
      refetchOnReconnect: strategy.refetchOnReconnect,
      retry: strategy.retry,
      retryDelay: strategy.retryDelay,
    },
  },
});

2.3 内存管理优化

interface CacheConfig {
  maxSize: number;           // 最大缓存项数
  maxMemoryBytes: number;    // 最大内存占用(字节)
  gcInterval: number;        // GC清理间隔(毫秒)
}

class OpenHarmonyCacheManager {
  private cache = new Map<string, { data: any; size: number; lastAccess: number }>();
  private config: CacheConfig;
  private currentMemoryUsage = 0;
  private gcTimer: NodeJS.Timeout | null = null;

  constructor(config: CacheConfig) {
    this.config = {
      maxSize: config.maxSize || 100,
      maxMemoryBytes: config.maxMemoryBytes || 10 * 1024 * 1024, // 10MB
      gcInterval: config.gcInterval || 60000, // 1分钟
    };

    this.startGC();
  }

  // 估算对象大小
  private estimateSize(obj: any): number {
    return JSON.stringify(obj).length * 2; // UTF-16编码
  }

  // 设置缓存
  set(key: string, data: any): void {
    const size = this.estimateSize(data);

    // 检查是否超过单条限制
    if (size > this.config.maxMemoryBytes / 10) {
      console.warn(`Cache item too large: ${key}`);
      return;
    }

    // 更新内存使用
    if (this.cache.has(key)) {
      this.currentMemoryUsage -= this.cache.get(key)!.size;
    }
    this.currentMemoryUsage += size;

    // 设置缓存
    this.cache.set(key, {
      data,
      size,
      lastAccess: Date.now(),
    });

    // 触发清理
    if (this.currentMemoryUsage > this.config.maxMemoryBytes ||
        this.cache.size > this.config.maxSize) {
      this.evict();
    }
  }

  // 获取缓存
  get(key: string): any | null {
    const entry = this.cache.get(key);
    if (entry) {
      entry.lastAccess = Date.now();
      return entry.data;
    }
    return null;
  }

  // 淘汰策略
  private evict(): void {
    const entries = Array.from(this.cache.entries());

    // 按最后访问时间排序(LRU)
    entries.sort((a, b) => a[1].lastAccess - b[1].lastAccess);

    // 移除最旧的30%
    const removeCount = Math.ceil(entries.length * 0.3);

    for (let i = 0; i < removeCount; i++) {
      const [key, entry] = entries[i];
      this.cache.delete(key);
      this.currentMemoryUsage -= entry.size;
    }

    console.log(`Cache evicted: ${removeCount} items, freed memory: ${this.currentMemoryUsage}`);
  }

  // 定期GC
  private startGC(): void {
    this.gcTimer = setInterval(() => {
      const now = Date.now();
      const staleThreshold = now - 300000; // 5分钟未访问

      for (const [key, entry] of this.cache.entries()) {
        if (entry.lastAccess < staleThreshold) {
          this.cache.delete(key);
          this.currentMemoryUsage -= entry.size;
        }
      }
    }, this.config.gcInterval);
  }

  // 清理资源
  destroy(): void {
    if (this.gcTimer) {
      clearInterval(this.gcTimer);
      this.gcTimer = null;
    }
    this.cache.clear();
    this.currentMemoryUsage = 0;
  }

  getStats() {
    return {
      size: this.cache.size,
      memoryUsage: this.currentMemoryUsage,
      memoryUsagePercent: (this.currentMemoryUsage / this.config.maxMemoryBytes * 100).toFixed(2),
    };
  }
}

三、持久化缓存方案

3.1 Preferences API集成

import preferences from '@ohos.data.preferences';

interface PersistedCacheEntry {
  data: any;
  timestamp: number;
  queryHash: string;
}

class OpenHarmonyPersistor {
  private store: preferences.Preferences | null = null;
  private readonly STORE_NAME = 'tanstack_query_cache';
  private memoryCache = new Map<string, PersistedCacheEntry>();

  async init(): Promise<void> {
    try {
      this.store = await preferences.getPreferences(
        globalThis.context,
        this.STORE_NAME
      );

      // 加载已持久化的缓存
      await this.loadPersistedCache();
    } catch (error) {
      console.error('Failed to initialize persistor:', error);
    }
  }

  private async loadPersistedCache(): Promise<void> {
    if (!this.store) return;

    try {
      const all = await this.store.all();

      for (const [key, value] of Object.entries(all)) {
        if (typeof value === 'string') {
          try {
            const entry: PersistedCacheEntry = JSON.parse(value);
            // 检查是否过期(24小时)
            const isExpired = Date.now() - entry.timestamp > 86400000;

            if (!isExpired) {
              this.memoryCache.set(key, entry);
            } else {
              await this.store!.delete(key);
            }
          } catch {
            // 忽略解析错误
          }
        }
      }

      await this.store.flush();
    } catch (error) {
      console.error('Failed to load persisted cache:', error);
    }
  }

  async persist(key: string, data: any, queryHash: string): Promise<void> {
    // 更新内存缓存
    const entry: PersistedCacheEntry = {
      data,
      timestamp: Date.now(),
      queryHash,
    };
    this.memoryCache.set(key, entry);

    // 持久化到Preferences
    if (this.store) {
      try {
        await this.store.put(key, JSON.stringify(entry));
        await this.store.flush();
      } catch (error) {
        console.error('Failed to persist cache:', error);
      }
    }
  }

  async restore(key: string): Promise<any | null> {
    // 先查内存
    if (this.memoryCache.has(key)) {
      return this.memoryCache.get(key)!.data;
    }

    // 再查持久化存储
    if (this.store) {
      try {
        const value = await this.store.get(key, '');
        if (value) {
          const entry: PersistedCacheEntry = JSON.parse(value as string);
          this.memoryCache.set(key, entry);
          return entry.data;
        }
      } catch {
        return null;
      }
    }

    return null;
  }

  async remove(key: string): Promise<void> {
    this.memoryCache.delete(key);

    if (this.store) {
      await this.store.delete(key);
      await this.store.flush();
    }
  }

  async clear(): Promise<void> {
    this.memoryCache.clear();

    if (this.store) {
      await this.store.clear();
      await this.store.flush();
    }
  }
}

// 与QueryClient集成
const persistor = new OpenHarmonyPersistor();
await persistor.init();

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      cacheTime: 120000, // 2分钟
      onSuccess: async (data, query) {
        // 持久化成功的查询结果
        const cacheKey = query.queryHash;
        await persistor.persist(cacheKey, data, query.queryHash);
      },
    },
  },
});

3.2 持久化方案对比

方案 容量 性能 复杂度 OpenHarmony兼容 适用场景
Preferences ~50KB ⚡⚡⚡ 原生支持 小型配置、用户信息
RDB数据库 无限制 ⚡⚡ 原生支持 大型列表、历史记录
文件存储 无限制 原生支持 图片、文档缓存
分布式缓存 无限制 特性支持 多设备同步

四、完整实战案例

以下是一个完整的TanStack Query缓存策略示例,专为OpenHarmony 6.0.0优化:

/**
 * TanStack Query缓存策略 - React Native for OpenHarmony
 *
 * @platform OpenHarmony 6.0.0 (API 20)
 * @react-native 0.72.5
 * @typescript 4.8.4
 */

import React, { useState, useCallback, useEffect, useRef } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
  ScrollView,
  Platform,
  ActivityIndicator,
} from 'react-native';

interface Props {
  onBack: () => void;
}

// 缓存数据类型
interface CacheData {
  data: any;
  timestamp: number;
  staleTime: number;
  cacheTime: number;
  hitCount: number;
}

// 网络类型
type NetworkType = 'WIFI' | 'CELLULAR_4G' | 'CELLULAR_3G' | 'NONE';

// 缓存策略配置
interface CacheStrategy {
  staleTime: number;
  cacheTime: number;
  refetchOnMount: boolean;
  refetchOnWindowFocus: boolean;
  refetchOnReconnect: boolean;
  retry: number;
  retryDelay: number;
}

// 模块级缓存存储
const queryCache = new Map<string, CacheData>();

// TanStack Query缓存策略演示组件
const TanStackQueryCacheScreen: React.FC<Props> = ({ onBack }) => {
  const [networkType, setNetworkType] = useState<NetworkType>('WIFI');
  const [currentStrategy, setCurrentStrategy] = useState<CacheStrategy>({
    staleTime: 60000,
    cacheTime: 300000,
    refetchOnMount: true,
    refetchOnWindowFocus: false,
    refetchOnReconnect: true,
    retry: 2,
    retryDelay: 1000,
  });

  const [queryData, setQueryData] = useState<any>(null);
  const [isFetching, setIsFetching] = useState(false);
  const [isRefetching, setIsRefetching] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [cacheHit, setCacheHit] = useState(false);
  const [requestCount, setRequestCount] = useState(0);
  const [cacheHits, setCacheHits] = useState(0);

  // 根据网络类型获取缓存策略
  const getStrategyForNetwork = useCallback((network: NetworkType): CacheStrategy => {
    const strategies: Record<NetworkType, CacheStrategy> = {
      WIFI: {
        staleTime: 60000,
        cacheTime: 300000,
        refetchOnMount: true,
        refetchOnWindowFocus: false,
        refetchOnReconnect: true,
        retry: 2,
        retryDelay: 1000,
      },
      CELLULAR_4G: {
        staleTime: 30000,
        cacheTime: 120000,
        refetchOnMount: true,
        refetchOnWindowFocus: false,
        refetchOnReconnect: true,
        retry: 1,
        retryDelay: 2000,
      },
      CELLULAR_3G: {
        staleTime: 15000,
        cacheTime: 60000,
        refetchOnMount: false,
        refetchOnWindowFocus: false,
        refetchOnReconnect: false,
        retry: 1,
        retryDelay: 3000,
      },
      NONE: {
        staleTime: Infinity,
        cacheTime: 600000,
        refetchOnMount: false,
        refetchOnWindowFocus: false,
        refetchOnReconnect: true,
        retry: 0,
        retryDelay: 0,
      },
    };
    return strategies[network];
  }, []);

  // 模拟数据获取
  const fetchData = useCallback(async (useCache = true): Promise<any> => {
    const cacheKey = 'user-data';
    const now = Date.now();

    // 检查缓存
    if (useCache) {
      const cached = queryCache.get(cacheKey);
      if (cached) {
        const isStale = now - cached.timestamp > cached.staleTime;
        const isExpired = now - cached.timestamp > cached.cacheTime;

        if (!isExpired) {
          setCacheHit(true);
          setCacheHits(prev => prev + 1);
          return cached.data;
        }
        // 过期则删除缓存
        queryCache.delete(cacheKey);
      }
    }

    setCacheHit(false);
    setRequestCount(prev => prev + 1);

    // 模拟网络延迟
    await new Promise(resolve => setTimeout(resolve, 800));

    // 模拟API响应
    return {
      id: '123',
      name: '张三',
      email: 'zhangsan@example.com',
      role: '高级工程师',
      status: 'online',
      lastUpdated: new Date().toLocaleString('zh-CN'),
    };
  }, []);

  // 执行查询
  const executeQuery = useCallback(async (refetch = false) => {
    if (refetch) {
      setIsRefetching(true);
    } else {
      setIsFetching(true);
    }
    setError(null);

    try {
      const data = await fetchData(!refetch);

      // 更新缓存
      queryCache.set('user-data', {
        data,
        timestamp: Date.now(),
        staleTime: currentStrategy.staleTime,
        cacheTime: currentStrategy.cacheTime,
        hitCount: 0,
      });

      setQueryData(data);
    } catch (err) {
      setError(err instanceof Error ? err.message : '请求失败');
    } finally {
      setIsFetching(false);
      setIsRefetching(false);
    }
  }, [fetchData, currentStrategy]);

  // 无效化缓存
  const invalidateCache = useCallback(() => {
    queryCache.clear();
    setCacheHits(0);
    executeQuery(true);
  }, [executeQuery]);

  // 切换网络类型
  const handleNetworkChange = useCallback((network: NetworkType) => {
    setNetworkType(network);
    const newStrategy = getStrategyForNetwork(network);
    setCurrentStrategy(newStrategy);
  }, [getStrategyForNetwork]);

  // 初始加载
  useEffect(() => {
    executeQuery();
  }, []);

  // 格式化时间
  const formatTime = (ms: number): string => {
    if (ms === Infinity) return '永久';
    if (ms >= 60000) return `${Math.floor(ms / 60000)}分钟`;
    if (ms >= 1000) return `${Math.floor(ms / 1000)}`;
    return `${ms}毫秒`;
  };

  // 缓存策略参数
  const strategyParams = [
    { key: 'staleTime', label: '数据新鲜时间', desc: '数据被视为fresh的时间', value: formatTime(currentStrategy.staleTime) },
    { key: 'cacheTime', label: '缓存保留时间', desc: '缓存数据保留时间', value: formatTime(currentStrategy.cacheTime) },
    { key: 'refetchOnMount', label: '挂载时刷新', desc: '组件挂载时重新获取', value: currentStrategy.refetchOnMount ? '开启' : '关闭' },
    { key: 'refetchOnWindowFocus', label: '前台时刷新', desc: '应用回到前台时刷新', value: currentStrategy.refetchOnWindowFocus ? '开启' : '关闭' },
    { key: 'refetchOnReconnect', label: '重连时刷新', desc: '网络重连时刷新', value: currentStrategy.refetchOnReconnect ? '开启' : '关闭' },
    { key: 'retry', label: '重试次数', desc: '请求失败时重试次数', value: currentStrategy.retry.toString() },
  ];

  // 网络类型配置
  const networkConfigs = [
    { type: 'WIFI' as NetworkType, label: 'WIFI', icon: '📶', desc: '高速网络', color: '#4CAF50' },
    { type: 'CELLULAR_4G' as NetworkType, label: '4G', icon: '📡', desc: '移动网络', color: '#2196F3' },
    { type: 'CELLULAR_3G' as NetworkType, label: '3G', icon: '📱', desc: '低速网络', color: '#FF9800' },
    { type: 'NONE' as NetworkType, label: '离线', icon: '📴', desc: '无网络', color: '#9E9E9E' },
  ];

  return (
    <ScrollView style={styles.container}>
      {/* 头部 */}
      <View style={styles.header}>
        <TouchableOpacity onPress={onBack} style={styles.backButton}>
          <Text style={styles.backButtonText}>← 返回</Text>
        </TouchableOpacity>
        <View style={styles.headerContent}>
          <Text style={styles.headerTitle}>TanStack Query缓存策略</Text>
          <Text style={styles.headerSubtitle}>Cache Strategy for OpenHarmony</Text>
        </View>
      </View>

      {/* 平台信息 */}
      <View style={styles.platformInfo}>
        <Text style={styles.platformText}>
          Platform: {Platform.OS} | OpenHarmony 6.0.0 (API 20)
        </Text>
      </View>

      {/* 核心概念 */}
      <View style={styles.section}>
        <Text style={styles.sectionTitle}>缓存核心概念</Text>
        <View style={styles.conceptGrid}>
          <View style={styles.conceptCard}>
            <Text style={styles.conceptIcon}>🆕</Text>
            <Text style={styles.conceptName}>Fresh</Text>
            <Text style={styles.conceptDesc}>数据新鲜</Text>
          </View>
          <View style={styles.conceptCard}>
            <Text style={styles.conceptIcon}>📅</Text>
            <Text style={styles.conceptName}>Stale</Text>
            <Text style={styles.conceptDesc}>数据过期</Text>
          </View>
          <View style={styles.conceptCard}>
            <Text style={styles.conceptIcon}>🔄</Text>
            <Text style={styles.conceptName}>Refetch</Text>
            <Text style={styles.conceptDesc}>重新获取</Text>
          </View>
          <View style={styles.conceptCard}>
            <Text style={styles.conceptIcon}>💾</Text>
            <Text style={styles.conceptName}>Cache</Text>
            <Text style={styles.conceptDesc}>缓存存储</Text>
          </View>
        </View>
      </View>

      {/* 网络类型选择 */}
      <View style={styles.section}>
        <Text style={styles.sectionTitle}>网络类型感知缓存</Text>
        <View style={styles.networkGrid}>
          {networkConfigs.map((config) => (
            <TouchableOpacity
              key={config.type}
              style={[
                styles.networkCard,
                networkType === config.type && { borderColor: config.color, backgroundColor: `${config.color}15` }
              ]}
              onPress={() => handleNetworkChange(config.type)}
            >
              <Text style={styles.networkIcon}>{config.icon}</Text>
              <Text style={styles.networkLabel}>{config.label}</Text>
              <Text style={styles.networkDesc}>{config.desc}</Text>
            </TouchableOpacity>
          ))}
        </View>
      </View>

      {/* 当前缓存策略 */}
      <View style={styles.section}>
        <Text style={styles.sectionTitle}>当前缓存策略 ({networkType})</Text>
        <View style={styles.strategyContainer}>
          {strategyParams.map((param) => (
            <View key={param.key} style={styles.paramRow}>
              <View style={styles.paramLeft}>
                <Text style={styles.paramLabel}>{param.label}</Text>
                <Text style={styles.paramDesc}>{param.desc}</Text>
              </View>
              <View style={styles.paramValueContainer}>
                <Text style={styles.paramValue}>{param.value}</Text>
              </View>
            </View>
          ))}
        </View>
      </View>

      {/* 查询数据 */}
      <View style={styles.section}>
        <Text style={styles.sectionTitle}>查询结果</Text>
        <View style={styles.queryResult}>
          {/* 状态指示 */}
          <View style={styles.statusBar}>
            <View style={styles.statusIndicator}>
              <View
                style={[
                  styles.statusDot,
                  isFetching && { backgroundColor: '#FF9800' },
                  queryData && !error && { backgroundColor: '#4CAF50' },
                  error && { backgroundColor: '#f44336' },
                ]}
              />
              <Text style={styles.statusText}>
                {isFetching ? '加载中' : error ? '错误' : queryData ? '成功' : '空闲'}
              </Text>
            </View>
            {isFetching && <ActivityIndicator size="small" color="#FF9800" />}
          </View>

          {/* 数据内容 */}
          {queryData && !error && (
            <View style={styles.dataContent}>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>姓名</Text>
                <Text style={styles.dataValue}>{queryData.name}</Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>邮箱</Text>
                <Text style={styles.dataValue}>{queryData.email}</Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>角色</Text>
                <Text style={styles.dataValue}>{queryData.role}</Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>状态</Text>
                <Text style={[styles.dataValue, queryData.status === 'online' && styles.statusOnline]}>
                  {queryData.status === 'online' ? '在线' : '离线'}
                </Text>
              </View>
              <View style={styles.dataRow}>
                <Text style={styles.dataLabel}>更新时间</Text>
                <Text style={styles.dataValue}>{queryData.lastUpdated}</Text>
              </View>

              {/* 缓存状态 */}
              <View style={styles.cacheStatus}>
                <Text style={styles.cacheIcon}>{cacheHit ? '💾' : '🌐'}</Text>
                <Text style={styles.cacheText}>
                  {cacheHit ? `来自缓存 | 命中: ${cacheHits + 1}` : `来自网络 | 请求: ${requestCount}`}
                </Text>
              </View>

              {isRefetching && (
                <View style={styles.refreshingIndicator}>
                  <ActivityIndicator size="small" color="#FF9800" />
                  <Text style={styles.refreshingText}>正在后台刷新...</Text>
                </View>
              )}
            </View>
          )}

          {/* 错误状态 */}
          {error && (
            <View style={styles.errorContent}>
              <Text style={styles.errorIcon}></Text>
              <Text style={styles.errorText}>{error}</Text>
            </View>
          )}

          {/* 操作按钮 */}
          <View style={styles.actionButtons}>
            <TouchableOpacity
              style={styles.actionButton}
              onPress={() => executeQuery(false)}
              disabled={isFetching}
            >
              <Text style={styles.actionButtonText}>加载数据</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={[styles.actionButton, styles.actionButtonSecondary]}
              onPress={() => executeQuery(true)}
              disabled={isFetching}
            >
              <Text style={styles.actionButtonText}>强制刷新</Text>
            </TouchableOpacity>
            <TouchableOpacity
              style={[styles.actionButton, styles.actionButtonDanger]}
              onPress={invalidateCache}
              disabled={isFetching}
            >
              <Text style={styles.actionButtonText}>清除缓存</Text>
            </TouchableOpacity>
          </View>
        </View>
      </View>

      {/* OpenHarmony适配要点 */}
      <View style={styles.section}>
        <Text style={styles.sectionTitle}>OpenHarmony 6.0.0 缓存优化</Text>
        <View style={styles.tipsContainer}>
          <View style={styles.tipItem}>
            <Text style={styles.tipIcon}>💡</Text>
            <View style={styles.tipContent}>
              <Text style={styles.tipTitle}>后台任务限制</Text>
              <Text style={styles.tipDesc}>将refetchOnWindowFocus设为false,避免后台刷新被限制</Text>
            </View>
          </View>
          <View style={styles.tipItem}>
            <Text style={styles.tipIcon}>💡</Text>
            <View style={styles.tipContent}>
              <Text style={styles.tipTitle}>内存管理严格</Text>
              <Text style={styles.tipDesc}>适当减少cacheTime,避免应用被系统终止</Text>
            </View>
          </View>
          <View style={styles.tipItem}>
            <Text style={styles.tipIcon}>💡</Text>
            <View style={styles.tipContent}>
              <Text style={styles.tipTitle}>网络状态感知</Text>
              <Text style={styles.tipDesc}>根据网络类型动态调整缓存策略参数</Text>
            </View>
          </View>
          <View style={styles.tipItem}>
            <Text style={styles.tipIcon}>💡</Text>
            <View style={styles.tipContent}>
              <Text style={styles.tipTitle}>持久化缓存</Text>
              <Text style={styles.tipDesc}>使用Preferences API实现离线缓存支持</Text>
            </View>
          </View>
        </View>
      </View>

      {/* 性能对比 */}
      <View style={styles.section}>
        <Text style={styles.sectionTitle}>缓存策略性能对比</Text>
        <View style={styles.performanceTable}>
          <View style={styles.tableHeader}>
            <Text style={styles.tableHeaderText}>策略</Text>
            <Text style={styles.tableHeaderText}>内存</Text>
            <Text style={styles.tableHeaderText}>请求</Text>
            <Text style={styles.tableHeaderText}>评分</Text>
          </View>
          {[
            { name: '无缓存', memory: '低', request: '高', score: 2 },
            { name: '基础缓存', memory: '中', request: '中', score: 5 },
            { name: '动态缓存', memory: '中高', request: '低', score: 8 },
            { name: '持久化', memory: '高', request: '最低', score: 9 },
          ].map((item) => (
            <View key={item.name} style={styles.tableRow}>
              <Text style={styles.tableCell}>{item.name}</Text>
              <Text style={styles.tableCell}>{item.memory}</Text>
              <Text style={styles.tableCell}>{item.request}</Text>
              <Text style={[styles.tableCell, styles.scoreCell]}>{item.score}/10</Text>
            </View>
          ))}
        </View>
      </View>

      {/* 底部说明 */}
      <View style={styles.footer}>
        <Text style={styles.footerText}>
          TanStack Query缓存策略在OpenHarmony上的最佳实践
        </Text>
        <Text style={styles.footerText}>
          根据网络状态动态调整,优化资源使用和用户体验
        </Text>
      </View>
    </ScrollView>
  );
};

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#f5f5f5',
  },
  header: {
    flexDirection: 'row',
    alignItems: 'center',
    padding: 16,
    backgroundColor: '#FF9800',
  },
  backButton: {
    padding: 8,
    marginRight: 8,
  },
  backButtonText: {
    color: '#ffffff',
    fontSize: 16,
  },
  headerContent: {
    flex: 1,
  },
  headerTitle: {
    fontSize: 18,
    fontWeight: '700',
    color: '#ffffff',
    marginBottom: 4,
  },
  headerSubtitle: {
    fontSize: 11,
    color: '#ffffff',
    opacity: 0.9,
  },
  platformInfo: {
    padding: 12,
    backgroundColor: '#fff3e0',
    alignItems: 'center',
  },
  platformText: {
    fontSize: 11,
    color: '#e65100',
  },
  section: {
    padding: 16,
  },
  sectionTitle: {
    fontSize: 16,
    fontWeight: '700',
    marginBottom: 12,
    color: '#333',
  },
  conceptGrid: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: 10,
  },
  conceptCard: {
    flex: 1,
    minWidth: 70,
    aspectRatio: 1,
    backgroundColor: '#ffffff',
    borderRadius: 10,
    alignItems: 'center',
    justifyContent: 'center',
    padding: 10,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 1 },
    shadowOpacity: 0.1,
    shadowRadius: 2,
    elevation: 2,
  },
  conceptIcon: {
    fontSize: 20,
    marginBottom: 6,
  },
  conceptName: {
    fontSize: 11,
    fontWeight: '600',
    color: '#333',
    marginBottom: 3,
  },
  conceptDesc: {
    fontSize: 9,
    color: '#999',
    textAlign: 'center',
  },
  networkGrid: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: 10,
  },
  networkCard: {
    flex: 1,
    minWidth: 80,
    backgroundColor: '#ffffff',
    borderRadius: 10,
    padding: 12,
    alignItems: 'center',
    borderWidth: 2,
    borderColor: 'transparent',
  },
  networkIcon: {
    fontSize: 24,
    marginBottom: 6,
  },
  networkLabel: {
    fontSize: 13,
    fontWeight: '600',
    color: '#333',
    marginBottom: 2,
  },
  networkDesc: {
    fontSize: 10,
    color: '#999',
  },
  strategyContainer: {
    backgroundColor: '#ffffff',
    borderRadius: 8,
    overflow: 'hidden',
  },
  paramRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
  },
  paramLeft: {
    flex: 1,
  },
  paramLabel: {
    fontSize: 13,
    color: '#333',
    marginBottom: 2,
  },
  paramDesc: {
    fontSize: 10,
    color: '#999',
  },
  paramValueContainer: {
    backgroundColor: '#fff3e0',
    paddingHorizontal: 10,
    paddingVertical: 4,
    borderRadius: 4,
  },
  paramValue: {
    fontSize: 12,
    fontWeight: '600',
    color: '#FF9800',
  },
  queryResult: {
    backgroundColor: '#ffffff',
    borderRadius: 12,
    overflow: 'hidden',
  },
  statusBar: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    alignItems: 'center',
    padding: 12,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
  },
  statusIndicator: {
    flexDirection: 'row',
    alignItems: 'center',
  },
  statusDot: {
    width: 8,
    height: 8,
    borderRadius: 4,
    backgroundColor: '#ccc',
    marginRight: 8,
  },
  statusText: {
    fontSize: 13,
    color: '#666',
  },
  dataContent: {
    padding: 16,
  },
  dataRow: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    marginBottom: 10,
  },
  dataLabel: {
    fontSize: 13,
    color: '#999',
  },
  dataValue: {
    fontSize: 13,
    color: '#333',
    fontWeight: '500',
  },
  statusOnline: {
    color: '#4CAF50',
  },
  cacheStatus: {
    flexDirection: 'row',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    padding: 10,
    marginTop: 10,
    gap: 8,
  },
  cacheIcon: {
    fontSize: 16,
  },
  cacheText: {
    fontSize: 12,
    color: '#666',
  },
  refreshingIndicator: {
    flexDirection: 'row',
    alignItems: 'center',
    justifyContent: 'center',
    marginTop: 12,
    gap: 8,
  },
  refreshingText: {
    fontSize: 12,
    color: '#FF9800',
  },
  errorContent: {
    padding: 20,
    alignItems: 'center',
  },
  errorIcon: {
    fontSize: 40,
    marginBottom: 10,
  },
  errorText: {
    fontSize: 14,
    color: '#f44336',
    textAlign: 'center',
  },
  actionButtons: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    gap: 8,
    padding: 12,
  },
  actionButton: {
    flex: 1,
    minWidth: 100,
    backgroundColor: '#FF9800',
    borderRadius: 8,
    padding: 12,
    alignItems: 'center',
  },
  actionButtonSecondary: {
    backgroundColor: '#795548',
  },
  actionButtonDanger: {
    backgroundColor: '#f44336',
  },
  actionButtonText: {
    color: '#ffffff',
    fontSize: 13,
    fontWeight: '600',
  },
  tipsContainer: {
    gap: 10,
  },
  tipItem: {
    flexDirection: 'row',
    backgroundColor: '#ffffff',
    borderRadius: 8,
    padding: 12,
    gap: 12,
  },
  tipIcon: {
    fontSize: 18,
  },
  tipContent: {
    flex: 1,
  },
  tipTitle: {
    fontSize: 13,
    fontWeight: '600',
    color: '#333',
    marginBottom: 2,
  },
  tipDesc: {
    fontSize: 12,
    color: '#666',
  },
  performanceTable: {
    backgroundColor: '#ffffff',
    borderRadius: 8,
    overflow: 'hidden',
  },
  tableHeader: {
    flexDirection: 'row',
    backgroundColor: '#FF9800',
    padding: 10,
  },
  tableHeaderText: {
    flex: 1,
    fontSize: 11,
    fontWeight: '700',
    color: '#ffffff',
    textAlign: 'center',
  },
  tableRow: {
    flexDirection: 'row',
    padding: 10,
    borderBottomWidth: 1,
    borderBottomColor: '#e0e0e0',
  },
  tableCell: {
    flex: 1,
    fontSize: 11,
    color: '#333',
    textAlign: 'center',
  },
  scoreCell: {
    fontWeight: '700',
    color: '#FF9800',
  },
  footer: {
    padding: 20,
    borderTopWidth: 1,
    borderTopColor: '#e0e0e0',
    alignItems: 'center',
  },
  footerText: {
    fontSize: 11,
    color: '#999',
    textAlign: 'center',
    marginBottom: 4,
  },
});

export default TanStackQueryCacheScreen;

五、OpenHarmony 6.0.0最佳实践总结

5.1 推荐配置组合

场景 staleTime cacheTime refetchOnWindowFocus refetchOnReconnect
WIFI网络 60000ms 300000ms false true
4G网络 30000ms 120000ms false true
3G网络 15000ms 60000ms false false
离线模式 Infinity 600000ms false true

5.2 性能优化检查清单

  • 设置refetchOnWindowFocus: false避免后台限制
  • 根据网络类型动态调整staleTime
  • 限制cacheTime避免内存占用过高
  • 实现LRU缓存淘汰策略
  • 集成Preferences API实现持久化
  • 监听网络状态变化动态调整策略
  • 设置合理的重试次数和延迟

5.3 常见问题解决方案

问题 OpenHarmony特殊原因 解决方案
应用被终止 内存占用过高 减少cacheTime,实现缓存大小限制
后台刷新失效 后台任务被限制 refetchOnWindowFocus: false
网络请求频繁 staleTime过短 增加staleTime或使用动态策略
缓存频繁丢失 内存被回收 实现持久化缓存

六、总结

TanStack Query在OpenHarmony 6.0.0平台上的缓存策略需要特别考虑:

  1. 后台任务限制:通过refetchOnWindowFocus: false避免系统限制
  2. 内存管理严格:适当减少cacheTime,实现缓存大小控制
  3. 网络状态感知:根据网络类型动态调整缓存参数
  4. 持久化支持:使用Preferences API实现离线缓存

核心配置公式

OpenHarmony最佳配置 = {
  staleTime: 根据网络类型动态调整(15s-60s),
  cacheTime: 固定2分钟避免内存问题,
  refetchOnWindowFocus: false (关键!),
  refetchOnReconnect: true,
  retry: 1-2次,
  retryDelay: 2-3秒
}

关键词:OpenHarmony、React Native、TanStack Query、缓存策略、网络感知、性能优化

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐