You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native中Supabase图片无法同步渲染的问题求助

解决React Native SwipeListView中图片逐个渲染时的加载状态问题

你当前的全局imageLoading状态只控制了列表整体的加载,但图片URL获取完成后,每个图片的网络加载是独立进行的,所以需要给每个图片项单独维护加载状态,具体实现如下:

1. 添加图片加载状态管理

在组件中新增一个状态对象,用于记录每个图片的加载状态:

import { useState } from 'react';

// ...

const [imageLoadingStates, setImageLoadingStates] = useState({});

2. 初始化加载状态

修改fetchImages函数,在开始获取URL时,将所有需要加载的图片标记为"加载中":

const fetchImages = async (recipes) => {
  if (!recipes) {
    return;
  }
  // 初始化所有图片的加载状态为true
  const initialLoadingStates = recipes.reduce((acc, recipe) => {
    if (recipe?.img) {
      acc[recipe.img] = true;
    }
    return acc;
  }, {});
  setImageLoadingStates(initialLoadingStates);

  const imageNames = recipes.map(recipe => recipe ? recipe.img : undefined);
  const urlPromises = imageNames.map(async (imageName) => {
    if (!imageName) {
      return;
    }
    const publicURL = supabase.storage.from('images').getPublicUrl(imageName);
    return { 
      name: imageName, 
      publicURL
    };
  });
  const urls = await Promise.all(urlPromises);
  setImageURLs(urls);
};

3. 封装图片加载状态的处理函数

添加两个函数,分别处理图片开始加载和加载结束(包括成功/失败)的状态更新:

const handleImageLoadStart = (imageName) => {
  setImageLoadingStates(prev => ({ ...prev, [imageName]: true }));
};

const handleImageLoadEnd = (imageName) => {
  setImageLoadingStates(prev => ({ ...prev, [imageName]: false }));
};

4. 修改图片渲染逻辑,添加加载指示器

在renderSwipeItem中,根据当前图片的加载状态,显示ActivityIndicator或图片:

const renderSwipeItem = ({ item, index }) => {
  const imageObj = imageURLs && imageURLs.find(imageObj => imageObj.name === item.img);
  const imageUrl = imageObj ? imageObj.publicURL.data.publicUrl : null;
  // 判断当前图片是否处于加载中,默认未加载时为true
  const isImageLoading = imageLoadingStates[item.img] ?? true;

  return (
    <View style={styles.container}>
      <List.Item
        key={index}
        title={item.name}
        titleNumberOfLines={2}
        titleEllipsizeMode='tail'
        left={() => (
          <View style={styles.listImageContainer}>
            {isImageLoading ? (
              <ActivityIndicator size="small" color="#0000ff" />
            ) : (
              <Image
                source={{ uri: imageUrl || null }}
                style={styles.listImage}
                onLoadStart={() => handleImageLoadStart(item.img)}
                onLoadEnd={() => handleImageLoadEnd(item.img)}
                onError={() => handleImageLoadEnd(item.img)} // 加载失败也结束状态
              />
            )}
          </View>
        )}
        onPress={() => navigation.navigate('Recipe', { 
          recipe: item,
          image: imageUrl || null,
        })}
        style={styles.listItem}
      />
    </View>
  )
};

5. 添加容器样式确保指示器居中

给图片容器添加固定尺寸和居中样式,让加载指示器在图片位置居中显示:

const styles = StyleSheet.create({
  // ... 其他样式
  listImageContainer: {
    width: 60,
    height: 60,
    borderRadius: 8,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#f0f0f0', // 灰色占位背景提升体验
  },
  listImage: {
    width: '100%',
    height: '100%',
    borderRadius: 8,
  },
});

效果说明

这样修改后,每个列表项的图片位置会先显示加载指示器,当图片加载完成(或失败)后,自动替换为图片,解决了图片逐个渲染时没有加载状态的问题。

内容的提问来源于stack exchange,提问作者JS_is_awesome18

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 17:43:12