or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

asset-management.mdindex.mdreact-hooks.mdstatic-loading.md
tile.json

react-hooks.mddocs/

React Hooks

React hook for declarative asset loading with automatic state management and error handling. Provides a React-friendly way to load assets with loading states and error reporting.

Capabilities

useAssets Hook

Downloads and stores one or more assets locally. After the assets are loaded, this hook returns a list of asset instances.

/**
 * Downloads and stores one or more assets locally.
 * After the assets are loaded, this hook returns a list of asset instances.
 * If something went wrong when loading the assets, an error is returned.
 *
 * Note: The assets are not "reloaded" when you dynamically change the asset list.
 *
 * @param moduleIds - Single module ID or array of module IDs to load
 * @returns Array containing:
 *   - assets: list of all loaded assets (undefined if not loaded yet)
 *   - error: error encountered when loading assets (undefined if no error)
 */
function useAssets(moduleIds: number | number[]): [Asset[] | undefined, Error | undefined];

Usage Examples:

import React from 'react';
import { Image, ActivityIndicator, Text, View } from 'react-native';
import { useAssets } from 'expo-asset';

// Basic usage with single asset
function SingleAssetComponent() {
  const [assets, error] = useAssets(require('./assets/logo.png'));

  if (error) {
    return <Text>Failed to load asset: {error.message}</Text>;
  }

  if (!assets) {
    return <ActivityIndicator />;
  }

  return <Image source={assets[0]} style={{ width: 100, height: 100 }} />;
}

// Multiple assets
function MultipleAssetsComponent() {
  const [assets, error] = useAssets([
    require('./assets/background.jpg'),
    require('./assets/icon.png'),
    require('./assets/overlay.png')
  ]);

  if (error) {
    console.error('Asset loading error:', error);
    return <Text>Could not load assets</Text>;
  }

  if (!assets) {
    return <ActivityIndicator size="large" />;
  }

  const [background, icon, overlay] = assets;

  return (
    <View>
      <Image source={background} style={styles.background} />
      <Image source={icon} style={styles.icon} />
      <Image source={overlay} style={styles.overlay} />
    </View>
  );
}

// Conditional rendering based on asset availability
function ConditionalAssetComponent() {
  const [assets, error] = useAssets([
    require('./assets/image1.png'),
    require('./assets/image2.png')
  ]);

  // Handle error state
  if (error) {
    return (
      <View>
        <Text>Asset loading failed</Text>
        <Text>Error: {error.message}</Text>
      </View>
    );
  }

  // Handle loading state
  if (!assets) {
    return (
      <View>
        <ActivityIndicator />
        <Text>Loading assets...</Text>
      </View>
    );
  }

  // Assets loaded successfully
  return (
    <View>
      {assets.map((asset, index) => (
        <Image
          key={index}
          source={asset}
          style={{ width: 100, height: 100, margin: 5 }}
        />
      ))}
    </View>
  );
}

// Using with asset metadata
function AssetInfoComponent() {
  const [assets, error] = useAssets(require('./assets/photo.jpg'));

  if (error || !assets) {
    return <Text>Loading...</Text>;
  }

  const [photo] = assets;

  return (
    <View>
      <Image source={photo} style={{ width: 200, height: 200 }} />
      <Text>Name: {photo.name}</Text>
      <Text>Type: {photo.type}</Text>
      <Text>Size: {photo.width} x {photo.height}</Text>
      <Text>Downloaded: {photo.downloaded ? 'Yes' : 'No'}</Text>
      <Text>Local URI: {photo.localUri}</Text>
    </View>
  );
}

Important Notes

Asset Caching

The useAssets hook does not reload assets when the asset list changes dynamically. If you need to load different assets based on state changes, you should use separate hook calls or manage asset loading manually with Asset.loadAsync.

// ❌ This won't reload when selectedAsset changes
function DynamicAssetComponent({ selectedAsset }) {
  const [assets, error] = useAssets(selectedAsset);
  // Assets won't update when selectedAsset prop changes
}

// ✅ Better approach for dynamic assets
import React, { useState, useEffect } from 'react';
import { Asset } from 'expo-asset';

function DynamicAssetComponent({ selectedAsset }) {
  const [asset, setAsset] = useState(null);
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    setLoading(true);
    setError(null);
    
    Asset.loadAsync(selectedAsset)
      .then(([loadedAsset]) => {
        setAsset(loadedAsset);
        setLoading(false);
      })
      .catch(err => {
        setError(err);
        setLoading(false);
      });
  }, [selectedAsset]);

  if (error) return <Text>Error: {error.message}</Text>;
  if (loading) return <ActivityIndicator />;
  
  return <Image source={asset} />;
}

Error Handling

Always handle both loading and error states when using useAssets:

function RobustAssetComponent() {
  const [assets, error] = useAssets([
    require('./assets/required-image.png')
  ]);

  // Always check error state first
  if (error) {
    console.error('Asset loading failed:', error);
    // Show fallback UI or retry mechanism
    return <Text>Could not load images</Text>;
  }

  // Then check loading state
  if (!assets) {
    return <ActivityIndicator />;
  }

  // Finally render with loaded assets
  return <Image source={assets[0]} />;
}