CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-react-loadable

A higher order component for loading components with promises

Pending
Overview
Eval results
Files

multi-resource-loading.mddocs/

Multi-Resource Loading

Advanced functionality for loading multiple resources in parallel using Loadable.Map. This enables complex loading scenarios where components depend on multiple modules, data sources, or external resources.

Capabilities

Loadable.Map Function

Creates a loadable component that loads multiple resources in parallel and provides them to a custom render function.

/**
 * Creates a loadable component that loads multiple resources in parallel
 * @param options - Configuration object with loader map and render function
 * @returns LoadableComponent class
 */
function LoadableMap(options: LoadableMapOptions): LoadableComponent;

interface LoadableMapOptions {
  /** Object mapping keys to loader functions */
  loader: { [key: string]: () => Promise<any> };
  /** Component to render during loading/error states */
  loading: LoadingComponent;
  /** Required render function to combine loaded resources */
  render: (loaded: { [key: string]: any }, props: any) => React.ReactElement;
  /** Delay in milliseconds before showing loading component (default: 200) */
  delay?: number;
  /** Timeout in milliseconds before showing timeout state (default: null) */  
  timeout?: number;
  /** Function returning webpack module IDs for SSR */
  webpack?: () => number[];
  /** Array of module paths for SSR */
  modules?: string[];
}

Usage Examples:

import React from 'react';
import Loadable from 'react-loadable';

// Load component and data together
const LoadableUserProfile = Loadable.Map({
  loader: {
    Component: () => import('./UserProfile'),
    translations: () => fetch('/api/i18n/user-profile.json').then(res => res.json()),
    theme: () => import('./themes/default'),
  },
  loading: LoadingSpinner,
  render(loaded, props) {
    const UserProfile = loaded.Component.default;
    return (
      <UserProfile
        {...props}
        translations={loaded.translations}
        theme={loaded.theme.default}
      />
    );
  },
});

// Load multiple related components
const LoadableDashboard = Loadable.Map({
  loader: {
    Header: () => import('./DashboardHeader'),
    Sidebar: () => import('./DashboardSidebar'),
    Content: () => import('./DashboardContent'),
  },
  loading: LoadingDashboard,
  render(loaded, props) {
    const Header = loaded.Header.default;
    const Sidebar = loaded.Sidebar.default;
    const Content = loaded.Content.default;
    
    return (
      <div className="dashboard">
        <Header user={props.user} />
        <div className="dashboard-body">
          <Sidebar />
          <Content data={props.data} />
        </div>
      </div>
    );
  },
});

Render Function

The render function is required for Loadable.Map and receives all loaded resources as a single object.

/**
 * Render function for combining multiple loaded resources
 * @param loaded - Object containing all loaded resources by key
 * @param props - Props passed to the LoadableComponent
 * @returns React element combining the loaded resources
 */
type LoadableMapRenderFunction = (
  loaded: { [key: string]: any },
  props: any
) => React.ReactElement;

Usage Examples:

// Complex data transformation
const LoadableChart = Loadable.Map({
  loader: {
    ChartComponent: () => import('./Chart'),
    data: () => fetch('/api/chart-data').then(res => res.json()),
    config: () => import('./chart-config.json'),
  },
  loading: Loading,
  render(loaded, props) {
    const Chart = loaded.ChartComponent.default;
    const processedData = processChartData(loaded.data, loaded.config);
    
    return <Chart data={processedData} {...props} />;
  },
});

// Conditional rendering based on loaded resources
const LoadableConditional = Loadable.Map({
  loader: {
    AdminPanel: () => import('./AdminPanel'),
    UserPanel: () => import('./UserPanel'),
    permissions: () => fetch('/api/user/permissions').then(res => res.json()),
  },
  loading: Loading,
  render(loaded, props) {
    const isAdmin = loaded.permissions.includes('admin');
    const Panel = isAdmin ? loaded.AdminPanel.default : loaded.UserPanel.default;
    
    return <Panel {...props} permissions={loaded.permissions} />;
  },
});

Loading States and Error Handling

Multi-resource loading handles complex scenarios where some resources may load faster than others or where individual resources may fail.

Loading Behavior

  • All resources start loading in parallel
  • The loading component is displayed until ALL resources complete
  • If any resource fails, the error state is triggered
  • Individual resource loading times don't affect the loading state display
// Loading component for multi-resource scenarios
function MultiResourceLoading(props) {
  if (props.error) {
    return (
      <div className="multi-load-error">
        <h3>Failed to load resources</h3>
        <p>One or more required resources failed to load</p>
        <button onClick={props.retry}>Retry All</button>
      </div>
    );
  }
  
  if (props.timedOut) {
    return (
      <div className="multi-load-timeout">
        <h3>Loading is taking longer than expected</h3>
        <button onClick={props.retry}>Retry</button>
      </div>
    );
  }
  
  if (props.pastDelay) {
    return (
      <div className="multi-load-loading">
        <div>Loading dashboard components...</div>
        <div className="loading-spinner" />
      </div>
    );
  }
  
  return null;
}

Advanced Patterns

Resource Dependencies

Handle scenarios where some resources depend on others by structuring the loader appropriately.

const LoadableWithDependencies = Loadable.Map({
  loader: {
    config: () => fetch('/api/config').then(res => res.json()),
    // Note: All loaders start simultaneously, but you can handle dependencies in render
    component: () => import('./ConfigurableComponent'),
  },
  loading: Loading,
  render(loaded, props) {
    const Component = loaded.component.default;
    
    // Apply configuration to component
    return <Component config={loaded.config} {...props} />;
  },
});

Dynamic Resource Loading

Combine static and dynamic resource loading based on props.

function createDynamicLoader(locale) {
  return Loadable.Map({
    loader: {
      Component: () => import('./LocalizedComponent'),
      translations: () => import(`./i18n/${locale}.json`),
      dateUtils: () => import(`./utils/date-${locale}.js`),
    },
    loading: Loading,
    render(loaded, props) {
      const Component = loaded.Component.default;
      return (
        <Component
          {...props}
          translations={loaded.translations}
          formatDate={loaded.dateUtils.formatDate}
        />
      );
    },
  });
}

// Usage
const LoadableEnglish = createDynamicLoader('en');
const LoadableFrench = createDynamicLoader('fr');

Mixed Resource Types

Load different types of resources including modules, JSON data, external APIs, and assets.

const LoadableRichContent = Loadable.Map({
  loader: {
    // React component
    Editor: () => import('./RichTextEditor'),
    
    // JSON configuration
    editorConfig: () => import('./editor-config.json'),
    
    // External API data
    userData: () => fetch('/api/user/preferences').then(res => res.json()),
    
    // Dynamic import based on feature flags
    plugins: () => 
      fetch('/api/feature-flags')
        .then(res => res.json())
        .then(flags => flags.advancedEditor ? 
          import('./editor-plugins/advanced') : 
          import('./editor-plugins/basic')
        ),
  },
  loading: RichContentLoading,
  render(loaded, props) {
    const Editor = loaded.Editor.default;
    
    return (
      <Editor
        {...props}
        config={loaded.editorConfig}
        userPreferences={loaded.userData}
        plugins={loaded.plugins.default}
      />
    );
  },
});

Install with Tessl CLI

npx tessl i tessl/npm-react-loadable

docs

build-integration.md

dynamic-loading.md

index.md

multi-resource-loading.md

server-side-rendering.md

tile.json