0
# Multi-Resource Loading
1
2
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.
3
4
## Capabilities
5
6
### Loadable.Map Function
7
8
Creates a loadable component that loads multiple resources in parallel and provides them to a custom render function.
9
10
```javascript { .api }
11
/**
12
* Creates a loadable component that loads multiple resources in parallel
13
* @param options - Configuration object with loader map and render function
14
* @returns LoadableComponent class
15
*/
16
function LoadableMap(options: LoadableMapOptions): LoadableComponent;
17
18
interface LoadableMapOptions {
19
/** Object mapping keys to loader functions */
20
loader: { [key: string]: () => Promise<any> };
21
/** Component to render during loading/error states */
22
loading: LoadingComponent;
23
/** Required render function to combine loaded resources */
24
render: (loaded: { [key: string]: any }, props: any) => React.ReactElement;
25
/** Delay in milliseconds before showing loading component (default: 200) */
26
delay?: number;
27
/** Timeout in milliseconds before showing timeout state (default: null) */
28
timeout?: number;
29
/** Function returning webpack module IDs for SSR */
30
webpack?: () => number[];
31
/** Array of module paths for SSR */
32
modules?: string[];
33
}
34
```
35
36
**Usage Examples:**
37
38
```javascript
39
import React from 'react';
40
import Loadable from 'react-loadable';
41
42
// Load component and data together
43
const LoadableUserProfile = Loadable.Map({
44
loader: {
45
Component: () => import('./UserProfile'),
46
translations: () => fetch('/api/i18n/user-profile.json').then(res => res.json()),
47
theme: () => import('./themes/default'),
48
},
49
loading: LoadingSpinner,
50
render(loaded, props) {
51
const UserProfile = loaded.Component.default;
52
return (
53
<UserProfile
54
{...props}
55
translations={loaded.translations}
56
theme={loaded.theme.default}
57
/>
58
);
59
},
60
});
61
62
// Load multiple related components
63
const LoadableDashboard = Loadable.Map({
64
loader: {
65
Header: () => import('./DashboardHeader'),
66
Sidebar: () => import('./DashboardSidebar'),
67
Content: () => import('./DashboardContent'),
68
},
69
loading: LoadingDashboard,
70
render(loaded, props) {
71
const Header = loaded.Header.default;
72
const Sidebar = loaded.Sidebar.default;
73
const Content = loaded.Content.default;
74
75
return (
76
<div className="dashboard">
77
<Header user={props.user} />
78
<div className="dashboard-body">
79
<Sidebar />
80
<Content data={props.data} />
81
</div>
82
</div>
83
);
84
},
85
});
86
```
87
88
### Render Function
89
90
The render function is required for `Loadable.Map` and receives all loaded resources as a single object.
91
92
```javascript { .api }
93
/**
94
* Render function for combining multiple loaded resources
95
* @param loaded - Object containing all loaded resources by key
96
* @param props - Props passed to the LoadableComponent
97
* @returns React element combining the loaded resources
98
*/
99
type LoadableMapRenderFunction = (
100
loaded: { [key: string]: any },
101
props: any
102
) => React.ReactElement;
103
```
104
105
**Usage Examples:**
106
107
```javascript
108
// Complex data transformation
109
const LoadableChart = Loadable.Map({
110
loader: {
111
ChartComponent: () => import('./Chart'),
112
data: () => fetch('/api/chart-data').then(res => res.json()),
113
config: () => import('./chart-config.json'),
114
},
115
loading: Loading,
116
render(loaded, props) {
117
const Chart = loaded.ChartComponent.default;
118
const processedData = processChartData(loaded.data, loaded.config);
119
120
return <Chart data={processedData} {...props} />;
121
},
122
});
123
124
// Conditional rendering based on loaded resources
125
const LoadableConditional = Loadable.Map({
126
loader: {
127
AdminPanel: () => import('./AdminPanel'),
128
UserPanel: () => import('./UserPanel'),
129
permissions: () => fetch('/api/user/permissions').then(res => res.json()),
130
},
131
loading: Loading,
132
render(loaded, props) {
133
const isAdmin = loaded.permissions.includes('admin');
134
const Panel = isAdmin ? loaded.AdminPanel.default : loaded.UserPanel.default;
135
136
return <Panel {...props} permissions={loaded.permissions} />;
137
},
138
});
139
```
140
141
## Loading States and Error Handling
142
143
Multi-resource loading handles complex scenarios where some resources may load faster than others or where individual resources may fail.
144
145
### Loading Behavior
146
147
- All resources start loading in parallel
148
- The loading component is displayed until ALL resources complete
149
- If any resource fails, the error state is triggered
150
- Individual resource loading times don't affect the loading state display
151
152
```javascript
153
// Loading component for multi-resource scenarios
154
function MultiResourceLoading(props) {
155
if (props.error) {
156
return (
157
<div className="multi-load-error">
158
<h3>Failed to load resources</h3>
159
<p>One or more required resources failed to load</p>
160
<button onClick={props.retry}>Retry All</button>
161
</div>
162
);
163
}
164
165
if (props.timedOut) {
166
return (
167
<div className="multi-load-timeout">
168
<h3>Loading is taking longer than expected</h3>
169
<button onClick={props.retry}>Retry</button>
170
</div>
171
);
172
}
173
174
if (props.pastDelay) {
175
return (
176
<div className="multi-load-loading">
177
<div>Loading dashboard components...</div>
178
<div className="loading-spinner" />
179
</div>
180
);
181
}
182
183
return null;
184
}
185
```
186
187
## Advanced Patterns
188
189
### Resource Dependencies
190
191
Handle scenarios where some resources depend on others by structuring the loader appropriately.
192
193
```javascript
194
const LoadableWithDependencies = Loadable.Map({
195
loader: {
196
config: () => fetch('/api/config').then(res => res.json()),
197
// Note: All loaders start simultaneously, but you can handle dependencies in render
198
component: () => import('./ConfigurableComponent'),
199
},
200
loading: Loading,
201
render(loaded, props) {
202
const Component = loaded.component.default;
203
204
// Apply configuration to component
205
return <Component config={loaded.config} {...props} />;
206
},
207
});
208
```
209
210
### Dynamic Resource Loading
211
212
Combine static and dynamic resource loading based on props.
213
214
```javascript
215
function createDynamicLoader(locale) {
216
return Loadable.Map({
217
loader: {
218
Component: () => import('./LocalizedComponent'),
219
translations: () => import(`./i18n/${locale}.json`),
220
dateUtils: () => import(`./utils/date-${locale}.js`),
221
},
222
loading: Loading,
223
render(loaded, props) {
224
const Component = loaded.Component.default;
225
return (
226
<Component
227
{...props}
228
translations={loaded.translations}
229
formatDate={loaded.dateUtils.formatDate}
230
/>
231
);
232
},
233
});
234
}
235
236
// Usage
237
const LoadableEnglish = createDynamicLoader('en');
238
const LoadableFrench = createDynamicLoader('fr');
239
```
240
241
### Mixed Resource Types
242
243
Load different types of resources including modules, JSON data, external APIs, and assets.
244
245
```javascript
246
const LoadableRichContent = Loadable.Map({
247
loader: {
248
// React component
249
Editor: () => import('./RichTextEditor'),
250
251
// JSON configuration
252
editorConfig: () => import('./editor-config.json'),
253
254
// External API data
255
userData: () => fetch('/api/user/preferences').then(res => res.json()),
256
257
// Dynamic import based on feature flags
258
plugins: () =>
259
fetch('/api/feature-flags')
260
.then(res => res.json())
261
.then(flags => flags.advancedEditor ?
262
import('./editor-plugins/advanced') :
263
import('./editor-plugins/basic')
264
),
265
},
266
loading: RichContentLoading,
267
render(loaded, props) {
268
const Editor = loaded.Editor.default;
269
270
return (
271
<Editor
272
{...props}
273
config={loaded.editorConfig}
274
userPreferences={loaded.userData}
275
plugins={loaded.plugins.default}
276
/>
277
);
278
},
279
});
280
```