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

使用react-native-tab-view时相册图片无法渲染的问题求助

问题

我使用expo-media-library在App内展示用户相册图片,同时通过react-native-tab-view以标签页形式展示多个相册。目前标签页能正常显示相册名称,但相册内的图片无法渲染。

查阅官方文档后,尝试基于renderScene和SceneMap实现动态路由,根据相册ID获取对应资源,但依然只能加载相册信息,图片渲染失败。

相关代码:

// image parameter here is the redux store for keeping the images that are selected by user so it shouldn't matter in our case

function AlbumTabs({ albums, image }) {
  const [index, setIndex] = useState(0);
  const [sceneAssets, setSceneAssets] = useState();
  const [routes, setRoutes] = useState([]);

  const renderScene = () => {
    SceneMap(
      albums.reduce((scenes, album) => {
        scenes[album.id] = <AlbumEntry album={album} image={image} />;
        console.log("scenes: ", scenes);

        return scenes;
      }, {})
    );
  };

  useEffect(() => {
    console.log("are we getting into render scene");
    // renderScene();

    const routeArray = albums.map((album) => {
      console.log("album.id: ", album.id);
      console.log("album.title: ", album.title);

      return {
        key: album.id,
        title: album.title,
      };
    });
    console.log("album length", albums.length);

    setRoutes(routeArray);
  }, [albums]);

  return (
    routes.length > 0 ? (
      <TabView
        renderTabBar={(props) => (
          <TabBar
            {...props}
            indicatorStyle={{ backgroundColor: "#EA9B3F" }}
            style={{ backgroundColor: "white", height: 50 }}
            scrollEnabled={true}
            renderLabel={({ route, color }) => (
              <Text style={{ color: "black", fontSize: 15, fontWeight: "500" }}>
                {route.title}
              </Text>
            )}
            
          />
        )}
        navigationState={{ index, routes }}
        renderScene={renderScene}
        onIndexChange={setIndex}
        initialLayout={initialLayout}
        lazy={true}
        style={styles.tabView}
      />
    ) : (
      <Text>Else body</Text>
    )
  );
}

// below component is supposed to render the images from a given album

function AlbumEntry({ album, image }) {
  const [assets, setAssets] = useState([]);
  const [selectedImages, setSelectedImages] = useState([]);
  const [loading, setLoading] = useState(true);
  const dispatch = useDispatch();

  useEffect(() => {
    if (image.value != undefined) {
      setSelectedImages(image.value);
    }
  }, [image]);

  async function getAlbumAssets() {
    setLoading(true);
    const albumAssets = await MediaLibrary.getAssetsAsync({
      album,
      first: 30,
    });
    setAssets(albumAssets.assets);
    
    setLoading(false);
  }

  useEffect(() => {
    console.log("album assets");
    getAlbumAssets();
  }, [album]);

  return (
    <View key={album.id} style={styles.albumContainer}>
      <Text allowFontScaling={false} style={styles.albumNameStyle}>
        {album.title}
      </Text>
      {loading ? (
        <ActivityIndicator size="small" color="#EA9B3F" />
      ) : (
        <View style={styles.albumAssetsContainer}>
          {assets.length === 0 ? (
            <Text allowFontScaling={false} style={styles.noResultsText}>
              0 results
            </Text>
          ) : (
            assets &&
            assets.map((_image) => (
                <Image
                  style={[
                    styles.imageStyle,
                    image.value != undefined
                      ? image.value.some(
                          (_uri) => _image.uri == _uri.original
                        ) && styles.selectedImage
                      : {},
                  ]}
                  source={{ uri: _image.uri }}
                  width={100}
                  height={100}
                />
              </TouchableOpacity>
            ))
          )}
        </View>
      )}
    </View>
  );
}
解决方法

1. 修复renderScene的实现问题

你的renderScene函数调用了SceneMap但未返回结果,导致TabView无法获取到要渲染的组件。同时,SceneMap要求每个场景值是一个返回React组件的函数,而非直接传入组件实例。

推荐改用更直观的动态渲染方式,直接根据当前route匹配对应的相册:

const renderScene = ({ route }) => {
  const targetAlbum = albums.find(album => album.id === route.key);
  if (!targetAlbum) return <Text>Album not found</Text>;
  return <AlbumEntry album={targetAlbum} image={image} />;
};

2. 修复AlbumEntry的JSX语法错误

assets.map中存在未闭合的TouchableOpacity标签,补全后才能正常渲染:

assets.map((_image) => (
  <TouchableOpacity key={_image.id} style={styles.imageWrapper}>
    <Image
      style={[
        styles.imageStyle,
        image.value != undefined
          ? image.value.some(_uri => _image.uri === _uri.original) && styles.selectedImage
          : {},
      ]}
      source={{ uri: _image.uri }}
      width={100}
      height={100}
    />
  </TouchableOpacity>
))

3. 检查权限配置

确保已经在app.json中配置了expo-media-library所需的权限:

{
  "expo": {
    "ios": {
      "infoPlist": {
        "NSPhotoLibraryUsageDescription": "需要访问您的相册以展示图片"
      }
    },
    "android": {
      "permissions": ["READ_MEDIA_IMAGES"]
    }
  }
}

4. 调试资源获取逻辑

在getAlbumAssets中添加日志并明确资源类型,确认是否成功获取到相册资源:

async function getAlbumAssets() {
  setLoading(true);
  try {
    const albumAssets = await MediaLibrary.getAssetsAsync({
      album,
      first: 30,
      mediaType: 'photo' // 明确指定只获取图片,避免混入视频等资源
    });
    console.log("获取到的相册资源:", albumAssets.assets);
    setAssets(albumAssets.assets);
  } catch (error) {
    console.error("获取相册资源失败:", error);
  } finally {
    setLoading(false);
  }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.19 15:23:11