ReactNative for OpenHarmony项目鸿蒙化三方库:react-native-fast-image — 高性能图片加载组件

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net
📌 开发环境声明:本文基于 React Native 0.72.90 版本进行开发适配


🚀 一、开篇引言

图片加载是最常见也是最影响性能的场景之一。React Native 内置的 Image 组件虽然能满足基本需求,但在处理大量图片、列表滚动等场景时往往表现不佳。react-native-fast-image 是一个高性能的图片加载组件,它封装了 iOS 的 SDWebImage 和 Android 的 Glide,提供了优秀的内存管理和缓存机制。本文将带你深入了解如何在 HarmonyOS 平台上集成和使用 react-native-fast-image,实现高效的图片加载体验。

1.1 你将学到什么?

  • ✅ react-native-fast-image 的核心概念与工作原理
  • ✅ HarmonyOS 平台的完整集成流程
  • ✅ 多种实战场景的代码实现(图片列表、头像组件、预加载优化)
  • ✅ 图片加载回调与错误处理
  • ✅ 缓存管理与性能优化

1.2 适用人群

  • 正在进行 React Native 鸿蒙化迁移的开发者
  • 需要优化图片加载性能的应用开发者
  • 对跨平台高性能组件开发感兴趣的技术爱好者

📦 二、库概览

2.1 基本信息

项目 内容
库名称 react-native-fast-image
维护方 DylanVann
最新版本 8.6.3 (RN 0.72)
RN 0.72 适配包 @react-native-oh-tpl/react-native-fast-image@8.6.3-0.4.17
官方仓库 https://github.com/DylanVann/react-native-fast-image
鸿蒙适配仓库 https://github.com/react-native-oh-library/react-native-fast-image
开源协议 MIT

2.2 核心能力矩阵

能力项 描述 HarmonyOS 支持
远程图片加载 支持网络 URL 加载 ✅ 完全支持
本地图片加载 支持本地资源加载 ✅ 完全支持
图片缓存 内存缓存和磁盘缓存 ✅ 完全支持
预加载 预加载图片到缓存 ✅ 完全支持
加载回调 开始、进度、完成、错误回调 ✅ 完全支持
优先级控制 加载优先级设置 ❌ 暂不支持
缓存策略 自定义缓存模式 ❌ 暂不支持
着色 图片颜色叠加 ✅ 完全支持

2.3 技术架构图

原生平台层
Bridge Layer
React Native 应用层
FastImage Component (JS/TS)
Props: source, resizeMode
Events: onLoad, onError
Methods: preload, clearCache
Native Module
FastImagePackage
FastImageViewManager
iOS

SDWebImage
Android

Glide
HarmonyOS

Image (ArkTS)

2.4 与同类方案对比

特性 react-native-fast-image React Native Image expo-image
HarmonyOS 支持 ✅ ✅ ⚠️ 需适配
内存缓存 ✅ 自动管理 ⚠️ 手动管理 ✅
磁盘缓存 ✅ 自动管理 ⚠️ 有限支持 ✅
预加载 ✅ ❌ ✅
加载进度 ✅ ❌ ✅
优先级控制 ✅ ❌ ✅
列表滚动性能 优秀 一般 优秀

⚡ 三、快速开始

3.1 环境要求

依赖项 版本要求
React Native 0.72.x
RNOH (鸿蒙框架) 0.72.90
HarmonyOS SDK 6.0.0.47+ (API 20)
DevEco Studio 5.0.3+ / 6.0+
Node.js 16.18.0+ / 18.x

3.2 版本说明

三方库版本 发布信息 支持RN版本
8.6.3-0.4.17 @react-native-oh-tpl/react-native-fast-image Releases 0.72

3.3 一键安装

创建鸿蒙项目的过程不在进行描述了,不懂得看这篇:https://blog.csdn.net/u011178696/article/details/151932277

bash 复制代码
# 安装鸿蒙适配包
npm install @react-native-oh-tpl/react-native-fast-image@8.6.3-0.4.17-rc.1

3.4 验证安装

bash 复制代码
# 检查 package.json
type package.json | findstr fast-image

# 预期输出
# "@react-native-oh-tpl/react-native-fast-image": "^8.6.3-0.4.17-rc.1"

🔧 四、HarmonyOS 集成详解

4.1 配置清单

📌 按顺序完成以下配置,缺一不可

步骤 配置文件 操作 重要程度
1 harmony/oh-package.json5 添加 overrides ⭐⭐⭐
2 harmony/entry/oh-package.json5 添加 har 依赖 ⭐⭐⭐
3 harmony/entry/src/main/cpp/CMakeLists.txt 配置编译链接 ⭐⭐⭐
4 harmony/entry/src/main/cpp/PackageProvider.cpp 引入头文件 ⭐⭐⭐
5 harmony/entry/src/main/ets/RNPackagesFactory.ts 引入 Package ⭐⭐⭐

💡 注意:react-native-fast-image 8.6.3-0.4.17 版本暂不支持 Autolink,需要手动配置原生依赖。

4.2 步骤详解(一定要根据自己的版本来)

步骤一:配置 overrides
json 复制代码
// 文件:harmony/oh-package.json5
{
  "name": "MyApplication",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {},
  "overrides": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}
步骤二:引入原生端代码

💡 提供两种引入方式,推荐使用 方法一(har 包引入)

方法一:通过 har 包引入(推荐)

📌 har 包位于三方库安装路径的 harmony 文件夹下

打开 harmony/entry/oh-package.json5,添加以下依赖:

json 复制代码
{
  "name": "entry",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90",
    "@react-native-oh-tpl/react-native-fast-image": "file:../../node_modules/@react-native-oh-tpl/react-native-fast-image/harmony/fast_image.har"
  }
}

点击 DevEco Studio 右上角的 Sync Now 按钮,或在终端执行:

bash 复制代码
cd harmony/entry
ohpm install
方法二:直接链接源码

📌 目前 DevEco Studio 不支持通过源码引入外部 module,需要将源码通过操作改成 harmony 工程的内部模块

步骤 1:复制源码到 harmony 工程根目录

将 <RN工程>/node_modules/@react-native-oh-tpl/react-native-fast-image/harmony/ 目录下的源码 fast_image 复制到 harmony 工程根目录下:

复制代码
harmony/
├── entry/
├── fast_image/          ← 复制过来的源码目录
└── build-profile.json5

步骤 2 :在 build-profile.json5 添加模块配置

打开 harmony/build-profile.json5,添加以下模块:

json 复制代码
{
  "app": {
    "signingConfigs": [],
    "products": [],
    "buildModeSet": []
  },
  "modules": [
    {
      "name": "entry",
      "srcPath": "./entry",
      "targets": []
    },
    {
      "name": "fast_image",
      "srcPath": "./fast_image"
    }
  ]
}

💡 如果存在 build-profile.template.json5 文件,也需要同步添加上述 modules 配置。

步骤 3:修改源码中的依赖版本

打开 harmony/fast_image/oh-package.json5,修改 @rnoh/react-native-openharmony 版本与项目一致:

json 复制代码
{
  "name": "fast_image",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90"
  }
}

步骤 4 :在 entry/oh-package.json5 添加依赖

打开 harmony/entry/oh-package.json5,添加以下依赖:

json 复制代码
{
  "name": "entry",
  "version": "1.0.0",
  "description": "Please describe the basic information.",
  "main": "",
  "author": "",
  "license": "",
  "dependencies": {
    "@rnoh/react-native-openharmony": "0.72.90",
    "@react-native-oh-tpl/react-native-fast-image": "file:../fast_image"
  }
}

步骤 5:同步项目

点击 DevEco Studio 右上角的 Sync Now 按钮,或在终端执行:

bash 复制代码
cd harmony/entry
ohpm install
步骤三:配置 CMake 编译
c 复制代码
# 文件:harmony/entry/src/main/cpp/CMakeLists.txt

project(rnapp)
cmake_minimum_required(VERSION 3.4.1)
set(CMAKE_SKIP_BUILD_RPATH TRUE)
set(RNOH_APP_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
set(NODE_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../node_modules")
+ set(OH_MODULES "${CMAKE_CURRENT_SOURCE_DIR}/../../../oh_modules")
set(RNOH_CPP_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../react-native-harmony/harmony/cpp")
set(LOG_VERBOSITY_LEVEL 1)
set(CMAKE_ASM_FLAGS "-Wno-error=unused-command-line-argument -Qunused-arguments")
set(CMAKE_CXX_FLAGS "-fstack-protector-strong -Wl,-z,relro,-z,now,-z,noexecstack -s -fPIE -pie")
set(WITH_HITRACE_SYSTRACE 1)
add_compile_definitions(WITH_HITRACE_SYSTRACE)

add_subdirectory("${RNOH_CPP_DIR}" ./rn)

# RNOH_BEGIN: manual_package_linking_1
add_subdirectory("../../../../sample_package/src/main/cpp" ./sample-package)
+ add_subdirectory("${OH_MODULES}/@react-native-oh-tpl/react-native-fast-image/src/main/cpp" ./fast-image)
# RNOH_END: manual_package_linking_1

file(GLOB GENERATED_CPP_FILES "./generated/*.cpp")

add_library(rnoh_app SHARED
    ${GENERATED_CPP_FILES}
    "./PackageProvider.cpp"
    "${RNOH_CPP_DIR}/RNOHAppNapiBridge.cpp"
)
target_link_libraries(rnoh_app PUBLIC rnoh)

# RNOH_BEGIN: manual_package_linking_2
target_link_libraries(rnoh_app PUBLIC rnoh_sample_package)
+ target_link_libraries(rnoh_app PUBLIC rnoh_fast_image)
# RNOH_END: manual_package_linking_2
步骤四:引入 Package(C++ 层)
cpp 复制代码
// 文件:harmony/entry/src/main/cpp/PackageProvider.cpp

#include "RNOH/PackageProvider.h"
#include "generated/RNOHGeneratedPackage.h"
#include "SamplePackage.h"
+ #include "FastImagePackage.h"

using namespace rnoh;

std::vector<std::shared_ptr<Package>> PackageProvider::getPackages(Package::Context ctx) {
    return {
        std::make_shared<RNOHGeneratedPackage>(ctx),
        std::make_shared<SamplePackage>(ctx),
        + std::make_shared<FastImagePackage>(ctx),
    };
}
步骤五:引入 Package(ArkTS 层)
typescript 复制代码
// 文件:harmony/entry/src/main/ets/RNPackagesFactory.ts

+ import { FastImagePackage } from '@react-native-oh-tpl/react-native-fast-image/ts';

export function createRNPackages(ctx: RNPackageContext): RNPackage[] {
  return [
    new SamplePackage(ctx),
    + new FastImagePackage(ctx)
  ];
}

4.3 同步与编译

bash 复制代码
# 进入 entry 目录
cd harmony/entry

# 执行依赖同步
ohpm install

# 返回项目根目录
cd ../..

在 DevEco Studio 中点击右上角的 Sync Now 按钮,等待同步完成后编译运行。

4.4 添加 harmony 运行环境

在项目中的 package.json 中添加运行命令,harmony 运行使用 npm run harmony 命令

json 复制代码
"scripts": {
  "android": "react-native run-android",
  "ios": "react-native run-ios",
  "lint": "eslint .",
  "start": "react-native start",
  "test": "jest",
  "harmony": "react-native bundle-harmony --dev"
},

💻 五、实战演练

场景一:基础图片加载

需求描述:实现一个基础的网络图片加载组件,支持加载状态显示和错误处理。

实现代码:

javascript 复制代码
import React, { useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  ActivityIndicator,
} from 'react-native';
import FastImage, {
  OnLoadEvent,
  OnProgressEvent,
} from 'react-native-fast-image';

interface ImageLoaderProps {
  uri: string;
  width?: number;
  height?: number;
  borderRadius?: number;
}

export default function ImageLoader({
  uri = "https://c-ssl.dtstatic.com/uploads/blog/202301/04/20230104230849_a9a24.thumb.400_0.jpeg",
  width = 200,
  height = 200,
  borderRadius = 8,
}: ImageLoaderProps) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(false);
  const [imageSize, setImageSize] = useState({ width: 0, height: 0 });

  const handleLoadStart = () => {
    setLoading(true);
    setError(false);
    console.log('图片开始加载');
  };

  const handleProgress = (event: OnProgressEvent) => {
    const { loaded, total } = event.nativeEvent;
    console.log(`加载进度: ${loaded}/${total}`);
  };

  const handleLoad = (event: OnLoadEvent) => {
    setLoading(false);
    const { width: w, height: h } = event.nativeEvent;
    setImageSize({ width: w, height: h });
    console.log(`图片加载完成: ${w}x${h}`);
  };

  const handleError = () => {
    setLoading(false);
    setError(true);
    console.log('图片加载失败');
  };

  const handleLoadEnd = () => {
    console.log('加载流程结束');
  };

  if (error) {
    return (
      <View style={[styles.errorContainer, { width, height, borderRadius }]}>
        <Text style={styles.errorText}>加载失败</Text>
      </View>
    );
  }

  return (
    <View style={[styles.container, { width, height, borderRadius }]}>
      <FastImage
        style={styles.image}
        source={{ uri }}
        resizeMode={FastImage.resizeMode.contain}
        onLoadStart={handleLoadStart}
        onProgress={handleProgress}
        onLoad={handleLoad}
        onError={handleError}
        onLoadEnd={handleLoadEnd}
      />
      {loading && (
        <View style={styles.loadingOverlay}>
          <ActivityIndicator size="large" color="#4c669f" />
        </View>
      )}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    overflow: 'hidden',
    backgroundColor: '#f0f0f0',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  loadingOverlay: {
    ...StyleSheet.absoluteFillObject,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: 'rgba(255,255,255,0.8)',
  },
  errorContainer: {
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f5f5f5',
    borderWidth: 1,
    borderColor: '#ddd',
  },
  errorText: {
    fontSize: 14,
    color: '#999',
  },
});

使用示例:

javascript 复制代码
import ImageLoader from './ImageLoader';

function App() {
  return (
    <View style={styles.container}>
      <ImageLoader
        uri="https://res8.vmallres.com/pimages/uomcdn/CN/pms/202205/gbom/6941487259298/428_428_D7BFF22D4678EB68440F914B352214C4mp_tds.png"
        width={300}
        height={300}
      />
    </View>
  );
}

场景二:图片列表优化

需求描述:实现一个高性能的图片列表,利用 FastImage 的缓存机制优化滚动性能。

实现代码:

javascript 复制代码
import React, { useCallback, useMemo } from 'react';
import {
  View,
  Text,
  StyleSheet,
  FlatList,
  TouchableOpacity,
} from 'react-native';
import FastImage from 'react-native-fast-image';

interface ImageItem {
  id: string;
  uri: string;
  title: string;
}

interface ImageGridProps {
  images: ImageItem[];
  onImagePress?: (item: ImageItem) => void;
  columns?: number;
}

export default function ImageGrid({
  images,
  onImagePress,
  columns = 2,
}: ImageGridProps) {
  const renderItem = useCallback(
    ({ item, index }: { item: ImageItem; index: number }) => {
      return (
        <TouchableOpacity
          style={styles.itemContainer}
          onPress={() => onImagePress?.(item)}
          activeOpacity={0.8}
        >
          <FastImage
            style={styles.image}
            source={{ uri: item.uri }}
            resizeMode={FastImage.resizeMode.cover}
          />
          <View style={styles.titleOverlay}>
            <Text style={styles.title} numberOfLines={1}>
              {item.title}
            </Text>
          </View>
        </TouchableOpacity>
      );
    },
    [onImagePress]
  );

  const keyExtractor = useCallback(
    (item: ImageItem) => item.id,
    []
  );

  const getItemLayout = useCallback(
    (_: any, index: number) => ({
      length: 200,
      offset: 200 * Math.floor(index / columns),
      index,
    }),
    [columns]
  );

  return (
    <FlatList
      data={images}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      numColumns={columns}
      getItemLayout={getItemLayout}
      showsVerticalScrollIndicator={false}
      contentContainerStyle={styles.listContainer}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews={true}
    />
  );
}

const styles = StyleSheet.create({
  listContainer: {
    padding: 8,
  },
  itemContainer: {
    flex: 1,
    margin: 4,
    height: 200,
    borderRadius: 12,
    overflow: 'hidden',
    backgroundColor: '#f0f0f0',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  titleOverlay: {
    position: 'absolute',
    bottom: 0,
    left: 0,
    right: 0,
    backgroundColor: 'rgba(0,0,0,0.6)',
    paddingVertical: 8,
    paddingHorizontal: 12,
  },
  title: {
    fontSize: 14,
    fontWeight: '500',
    color: '#FFFFFF',
  },
});

使用示例:

javascript 复制代码
// 补全所有缺失的引入
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import ImageGrid from './ImageGrid';

// 示例数据
const SAMPLE_IMAGES = [
  {
    id: '1',
    uri: 'https://picsum.photos/400/400?random=1',
    title: '风景照片',
  },
  {
    id: '2',
    uri: 'https://picsum.photos/400/400?random=2',
    title: '城市夜景',
  },
  {
    id: '3',
    uri: 'https://picsum.photos/400/400?random=3',
    title: '自然风光',
  },
  {
    id: '4',
    uri: 'https://picsum.photos/400/400?random=4',
    title: '建筑摄影',
  },
];

// 补全样式
function GalleryScreen() {
  const handleImagePress = (item: { id: string; uri: string; title: string }) => {
    console.log('点击图片:', item.title);
  };

  return (
    <View style={styles.container}>
      <Text style={styles.header}>图片画廊</Text>
      <ImageGrid
        images={SAMPLE_IMAGES}
        onImagePress={handleImagePress}
        columns={2}
      />
    </View>
  );
}

// 缺失的样式
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
  },
  header: {
    fontSize: 20,
    fontWeight: 'bold',
    padding: 16,
  },
});

export default GalleryScreen;

场景三:头像组件

需求描述:实现一个支持多种尺寸和样式的头像组件,支持默认头像和加载状态。

实现代码:

javascript 复制代码
import React, { useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
} from 'react-native';
import FastImage from 'react-native-fast-image';

type AvatarSize = 'small' | 'medium' | 'large' | 'xlarge';

interface AvatarProps {
  uri?: string;
  name?: string;
  size?: AvatarSize;
  borderRadius?: number;
  onPress?: () => void;
  showBorder?: boolean;
  borderColor?: string;
}

const SIZE_MAP: Record<AvatarSize, number> = {
  small: 32,
  medium: 48,
  large: 64,
  xlarge: 96,
};

const FONT_SIZE_MAP: Record<AvatarSize, number> = {
  small: 12,
  medium: 16,
  large: 20,
  xlarge: 32,
};

export default function Avatar({
  uri,
  name,
  size = 'medium',
  borderRadius,
  onPress,
  showBorder = false,
  borderColor = '#4c669f',
}: AvatarProps) {
  const [error, setError] = useState(false);
  const avatarSize = SIZE_MAP[size];
  const fontSize = FONT_SIZE_MAP[size];
  const actualBorderRadius = borderRadius ?? avatarSize / 2;

  const getInitials = (name: string): string => {
    const parts = name.trim().split(' ');
    if (parts.length >= 2) {
      return (parts[0][0] + parts[1][0]).toUpperCase();
    }
    return name.slice(0, 2).toUpperCase();
  };

  const renderPlaceholder = () => (
    <View
      style={[
        styles.placeholder,
        {
          width: avatarSize,
          height: avatarSize,
          borderRadius: actualBorderRadius,
        },
      ]}
    >
      <Text style={[styles.initials, { fontSize }]}>
        {name ? getInitials(name) : '?'}
      </Text>
    </View>
  );

  const content = (
    <View
      style={[
        styles.container,
        {
          width: avatarSize,
          height: avatarSize,
          borderRadius: actualBorderRadius,
        },
        showBorder && {
          borderWidth: 2,
          borderColor,
        },
      ]}
    >
      {uri && !error ? (
        <FastImage
          style={styles.image}
          source={{ uri }}
          resizeMode={FastImage.resizeMode.cover}
          onError={() => setError(true)}
        />
      ) : (
        renderPlaceholder()
      )}
    </View>
  );

  if (onPress) {
    return (
      <TouchableOpacity onPress={onPress} activeOpacity={0.8}>
        {content}
      </TouchableOpacity>
    );
  }

  return content;
}

const styles = StyleSheet.create({
  container: {
    overflow: 'hidden',
    backgroundColor: '#e0e0e0',
  },
  image: {
    width: '100%',
    height: '100%',
  },
  placeholder: {
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#4c669f',
  },
  initials: {
    fontWeight: '600',
    color: '#FFFFFF',
  },
});

使用示例:

javascript 复制代码
import React from 'react';
import { View, Text, StyleSheet } from 'react-native';
import Avatar from './Avatar';

function UserList() {
  const users = [
    { id: '1', name: '张三', avatar: 'https://i.pravatar.cc/150?img=1' },
    { id: '2', name: '李四', avatar: 'https://i.pravatar.cc/150?img=2' },
    { id: '3', name: '王五', avatar: '' },
    { id: '4', name: '赵六', avatar: 'https://i.pravatar.cc/150?img=4' },
  ];

  return (
    <View style={styles.container}>
      {users.map((user) => (
        <View key={user.id} style={styles.userItem}>
          <Avatar
            uri={user.avatar}
            name={user.name}
            size="large"
            showBorder
            onPress={() => console.log('点击用户:', user.name)}
          />
          <Text style={styles.userName}>{user.name}</Text>
        </View>
      ))}
    </View>
  );
}

// 补全缺失的样式
const styles = StyleSheet.create({
  container: {
    flex: 1,
    padding: 16,
    backgroundColor: '#fff',
  },
  userItem: {
    flexDirection: 'row',
    alignItems: 'center',
    marginBottom: 16,
    gap: 12,
  },
  userName: {
    fontSize: 16,
    color: '#333',
  },
});

export default UserList;

场景四:图片预加载与缓存管理

需求描述:实现图片预加载功能,提升用户体验,并提供缓存清理能力。

实现代码:

javascript 复制代码
import React, { useEffect, useState } from 'react';
import {
  View,
  Text,
  StyleSheet,
  TouchableOpacity,
  Alert,
} from 'react-native';
import FastImage from 'react-native-fast-image';

interface CacheManagerProps {
  preloadImages?: string[];
}

export default function CacheManager({ preloadImages = [] }: CacheManagerProps) {
  const [preloadStatus, setPreloadStatus] = useState<'idle' | 'loading' | 'done'>('idle');

  useEffect(() => {
    if (preloadImages.length > 0) {
      handlePreload();
    }
  }, []);

  const handlePreload = async () => {
    if (preloadImages.length === 0) {
      Alert.alert('提示', '没有需要预加载的图片');
      return;
    }

    setPreloadStatus('loading');
  
    try {
      const sources = preloadImages.map((uri) => ({ uri }));
      await FastImage.preload(sources);
      setPreloadStatus('done');
      Alert.alert('成功', `已预加载 ${preloadImages.length} 张图片`);
    } catch (error) {
      setPreloadStatus('idle');
      Alert.alert('错误', '预加载失败');
    }
  };

  const handleClearMemoryCache = async () => {
    try {
      await FastImage.clearMemoryCache();
      Alert.alert('成功', '内存缓存已清理');
    } catch (error) {
      Alert.alert('错误', '清理内存缓存失败');
    }
  };

  const handleClearDiskCache = async () => {
    try {
      await FastImage.clearDiskCache();
      Alert.alert('成功', '磁盘缓存已清理');
    } catch (error) {
      Alert.alert('错误', '清理磁盘缓存失败');
    }
  };

  return (
    <View style={styles.container}>
      <Text style={styles.title}>缓存管理</Text>
  
      <View style={styles.statusContainer}>
        <Text style={styles.statusText}>
          预加载状态: {
            preloadStatus === 'idle' ? '未开始' :
            preloadStatus === 'loading' ? '加载中...' : '已完成'
          }
        </Text>
      </View>

      <TouchableOpacity style={styles.button} onPress={handlePreload}>
        <Text style={styles.buttonText}>预加载图片</Text>
      </TouchableOpacity>

      <TouchableOpacity
        style={[styles.button, styles.clearButton]}
        onPress={handleClearMemoryCache}
      >
        <Text style={styles.buttonText}>清理内存缓存</Text>
      </TouchableOpacity>

      <TouchableOpacity
        style={[styles.button, styles.clearButton]}
        onPress={handleClearDiskCache}
      >
        <Text style={styles.buttonText}>清理磁盘缓存</Text>
      </TouchableOpacity>
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    padding: 16,
    backgroundColor: '#fff',
    borderRadius: 12,
    margin: 16,
  },
  title: {
    fontSize: 18,
    fontWeight: 'bold',
    marginBottom: 16,
    color: '#333',
  },
  statusContainer: {
    padding: 12,
    backgroundColor: '#f5f5f5',
    borderRadius: 8,
    marginBottom: 16,
  },
  statusText: {
    fontSize: 14,
    color: '#666',
  },
  button: {
    backgroundColor: '#4c669f',
    paddingVertical: 12,
    paddingHorizontal: 24,
    borderRadius: 8,
    marginBottom: 12,
    alignItems: 'center',
  },
  clearButton: {
    backgroundColor: '#e74c3c',
  },
  buttonText: {
    fontSize: 16,
    fontWeight: '600',
    color: '#FFFFFF',
  },
});

📋 六、API 详解

6.1 Props 属性

属性名 描述 类型 必填 HarmonyOS 支持
source.uri 远程图片地址 string 是 ✅
source.headers 请求头信息,如 { Authorization: 'token' } object 否 ✅
source.priority 加载优先级 enum 否 ❌
source.cache 缓存模式 enum 否 ❌
defaultSource 默认图片(本地资源) number 否 ✅
resizeMode 缩放模式 enum 否 ✅
onLoadStart 图片开始加载时触发 function 否 ✅
onProgress 图片加载过程中触发,返回加载进度 function 否 ✅
onLoad 图片加载成功时触发,返回图片宽高 function 否 ✅
onError 图片加载失败时触发 function 否 ✅
onLoadEnd 图片加载结束时触发(无论成功或失败) function 否 ✅
tintColor 图片着色,将非透明像素替换为指定颜色 string| number 否 ✅

6.2 resizeMode 枚举值

值 描述
contain 保持宽高比缩放,完整显示在容器内
cover 保持宽高比缩放,填满容器
stretch 拉伸图片填满容器,不保持宽高比
center 居中显示,不缩放

6.3 静态方法

方法名 描述 参数 HarmonyOS 支持
FastImage.preload 预加载图片到缓存 sources: { uri: string }\[\] ✅
FastImage.clearMemoryCache 清理内存缓存 无 ✅
FastImage.clearDiskCache 清理磁盘缓存 无 ✅

6.4 事件对象类型

typescript 复制代码
// 加载进度事件
interface OnProgressEvent {
  nativeEvent: {
    loaded: number;  // 已加载字节数
    total: number;   // 总字节数
  };
}

// 加载完成事件
interface OnLoadEvent {
  nativeEvent: {
    width: number;   // 图片宽度
    height: number;  // 图片高度
  };
}

⚠️ 七、常见问题与解决方案

7.1 图片不显示

问题描述:图片加载后不显示,或显示空白。

可能原因与解决方案:

  1. URL 格式问题

    javascript 复制代码
    // ❌ 错误:URL 缺少协议
    source={{ uri: 'example.com/image.png' }}
    
    // ✅ 正确:完整的 URL
    source={{ uri: 'https://example.com/image.png' }}
  2. 样式问题

    javascript 复制代码
    // ❌ 错误:未设置尺寸
    <FastImage source={{ uri }} />
    
    // ✅ 正确:设置明确的尺寸
    <FastImage style={{ width: 200, height: 200 }} source={{ uri }} />
  3. HTTPS 证书问题(Android)

    • 在 AndroidManifest.xml 中添加 android:usesCleartextTraffic="true"

7.2 图片加载缓慢

问题描述:首次加载图片时速度较慢。

解决方案:

  1. 使用预加载

    javascript 复制代码
    // 在应用启动时预加载常用图片
    FastImage.preload([
      { uri: 'https://example.com/avatar_default.png' },
      { uri: 'https://example.com/logo.png' },
    ]);
  2. 使用缩略图

    javascript 复制代码
    // 先加载小图,再加载大图
    <FastImage
      source={{ uri: thumbnailUrl }}
      onLoad={() => {
        // 加载完成后可以预加载高清图
        FastImage.preload([{ uri: highResUrl }]);
      }}
    />

7.3 内存占用过高

问题描述:应用内存占用持续增长。

解决方案:

javascript 复制代码
// 在合适的时机清理缓存
useEffect(() => {
  return () => {
    // 组件卸载时清理内存缓存
    FastImage.clearMemoryCache();
  };
}, []);

// 用户手动清理
const handleClearCache = async () => {
  await FastImage.clearMemoryCache();
  await FastImage.clearDiskCache();
};

7.4 HarmonyOS 特有问题

问题描述:部分属性在 HarmonyOS 上不支持。

解决方案:

不支持属性 替代方案
source.priority 暂无替代方案,默认按加载顺序处理
source.cache 暂无替代方案,使用默认缓存策略

📊 八、最佳实践

8.1 性能优化建议

  1. 合理设置图片尺寸

    javascript 复制代码
    // 根据容器大小选择合适的图片尺寸
    const getImageUrl = (baseUrl: string, size: number) => {
      return `${baseUrl}?w=${size}&h=${size}`;
    };
  2. 列表优化配置

    javascript 复制代码
    <FlatList
      data={images}
      renderItem={renderItem}
      keyExtractor={keyExtractor}
      initialNumToRender={10}
      maxToRenderPerBatch={10}
      windowSize={5}
      removeClippedSubviews={true}
      getItemLayout={getItemLayout}
    />
  3. 使用 React.memo 避免重复渲染

    javascript 复制代码
    const ImageItem = React.memo(({ uri, title }) => (
      <FastImage source={{ uri }} style={styles.image} />
    ));

8.2 错误处理规范

javascript 复制代码
const ImageWithErrorHandling = ({ uri }) => {
  const [error, setError] = useState(false);
  const [retryCount, setRetryCount] = useState(0);

  const handleError = () => {
    if (retryCount < 3) {
      setRetryCount(retryCount + 1);
    } else {
      setError(true);
    }
  };

  if (error) {
    return <DefaultImage />;
  }

  return (
    <FastImage
      key={`retry-${retryCount}`}
      source={{ uri }}
      onError={handleError}
    />
  );
};

8.3 TypeScript 类型定义

typescript 复制代码
import FastImage, {
  ResizeMode,
  OnLoadEvent,
  OnProgressEvent,
  Source,
} from 'react-native-fast-image';

interface CustomImageProps {
  source: Source | number;
  style?: StyleProp<ImageStyle>;
  resizeMode?: ResizeMode;
  onLoad?: (event: OnLoadEvent) => void;
  onError?: () => void;
}

🔗 九、参考资料


相关推荐
志尊宝12 小时前
AI原生前端开发(009):AI辅助性能分析与优化建议
人工智能·react.js·ai-native
lemon_yyds13 小时前
Vue 项目嵌入 React H5 技术方案
vue.js·react.js
用户294694054481616 小时前
DSH Desktop - Electron on HarmonyOS Edition
harmonyos·deepseek
IsITGirl18 小时前
HarmonyOS 鸿蒙 WuKong 稳定性测试报错 Failed to connect to AAMS(已解决)
华为·harmonyos
PHP是世界上最好的语言18 小时前
React接入PDF批注:保存后重新打开,确认改动没有丢
react.js
万物智能信息科技20 小时前
鸿蒙RS232驱动开发—【万物智能之开源鸿蒙OpenHarmony系统实战开发系列教程】
驱动开发·华为·开源·harmonyos·鸿蒙
用户298698530141 天前
在 React 中使用 JavaScript 将 Markdown 转换为 PDF
javascript·react.js·markdown
less_121381 天前
鸿蒙 WPS Open SDK 接入指南:凭据申请、HAR 集成与 registerApp 校验
华为·harmonyos·wps
Java后端的Ai之路1 天前
19-ReactJS最佳实践
前端·react.js·前端框架
威哥爱编程2 天前
HarmonyOS 7 Agent 开发实战 07:多 Agent 任务分解与反思
agent·harmonyos