4
4
5
5
[ ![ NPM] ( https://img.shields.io/npm/v/react-async-component-hoc.svg )] ( https://www.npmjs.com/package/react-async-component-hoc ) [ ![ JavaScript Style Guide] ( https://img.shields.io/badge/code_style-standard-brightgreen.svg )] ( https://standardjs.com )
6
6
7
-
8
-
9
7
This component is designed to make writing components that require complex async calls and
10
8
promise resolution obvious and easy to understand. It makes writing async components feel
11
9
much more like writing a normal component.
@@ -85,9 +83,10 @@ const XXX = createAsyncComponent(function MyComponent(props) {
85
83
}
86
84
})
87
85
```
86
+
88
87
### Using a fallback
89
88
90
- By default your component will be null until it is complete. There are two ways to override this:
89
+ By default your component will be null until it is complete. There are two ways to override this:
91
90
92
91
``` jsx
93
92
@@ -101,73 +100,79 @@ import {AsyncFallback} from 'react-async-component-hoc'
101
100
)
102
101
103
102
```
103
+
104
104
Using AsyncFallback allows you to specify anything to be rendered until your component is ready.
105
105
106
106
Alternatively your render function's props have a ` resolve ` function added which you can call at
107
107
any time to change what your component is rendering.
108
108
109
109
``` jsx
110
-
111
- const XXX = createAsyncComponent (function MyNewComponent ({resolve, url}) {
112
- return async ()=> {
113
- resolve (< h5> Running... .< / h5> )
114
- const result = await fetch (url)
115
- resolve (< h5> Fetched... .< / h5> )
116
- const data = await result .json ()
117
- return < div> {data .items .map (item => < div key= {item .id }> {item .data }< / div> )}< / div>
118
- }
119
- })
120
-
110
+ const XXX = createAsyncComponent (function MyNewComponent ({ resolve, url }) {
111
+ return async () => {
112
+ resolve (< h5> Running... .< / h5> )
113
+ const result = await fetch (url)
114
+ resolve (< h5> Fetched... .< / h5> )
115
+ const data = await result .json ()
116
+ return (
117
+ < div>
118
+ {data .items .map ((item ) => (
119
+ < div key= {item .id }> {item .data }< / div>
120
+ ))}
121
+ < / div>
122
+ )
123
+ }
124
+ })
121
125
```
122
126
123
127
### Using the built in template
124
128
125
129
If you only pass one function to createAsyncComponent it uses the built in BoxTemplate which allows
126
130
you to write a component that just returns a set of React elements which it will then render as shown
127
- above. It also allows you to render multiple parts of a result if you calculate incremental values.
131
+ above. It also allows you to render multiple parts of a result if you calculate incremental values.
128
132
129
- The built in template has a series of JSX components it renders. Each of these has a key. It renders
130
- the keys in order. If you just return is overwrites the one component being rendered which has a key of 0.
133
+ The built in template has a series of JSX components it renders. Each of these has a key. It renders
134
+ the keys in order. If you just return it overwrites the one component being rendered which has a key of 0.
131
135
132
136
``` jsx
137
+ const ExampleComponent3 = createAsyncComponent (async function MyComponent ({ resolve }) {
138
+ const order = [10 , 7 , 4 , 1 , 2 , 8 , 6 , 9 , 3 , 5 ]
139
+ for (let i = 0 ; i < 10 ; i++ ) {
140
+ let item = order[i]
141
+ resolve (
142
+ item,
143
+ < Box p= {1 }>
144
+ I am item index {item} - rendered in sequence {i + 1 }
145
+ < / Box>
146
+ )
133
147
134
- const ExampleComponent3 = createAsyncComponent (
135
- async function MyComponent ({ resolve }) {
136
- const order = [10 , 7 , 4 , 1 , 2 , 8 , 6 , 9 , 3 , 5 ]
137
- for (let i = 0 ; i < 10 ; i++ ) {
138
- let item = order[i]
148
+ if (i < 9 ) {
139
149
resolve (
140
- item ,
141
- < Box p = {1 }>
142
- I am item index {item} - rendered in sequence {i + 1 }
150
+ order[i + 1 ] ,
151
+ < Box ml = {1 }>
152
+ < CircularProgress color = { ' secondary ' } size = { 20 } / >
143
153
< / Box>
144
154
)
145
-
146
- if (i < 9 ) {
147
- resolve (order[i + 1 ], < Box ml= {1 }>< CircularProgress color= {" secondary" } size= {20 }/ >< / Box> )
148
- }
149
- await new Promise ((resolve ) => setTimeout (resolve, 1500 ))
150
155
}
156
+ await new Promise ((resolve ) => setTimeout (resolve, 1500 ))
151
157
}
152
- )
153
-
158
+ })
154
159
```
155
160
156
161
This component renders the items out of order, and renders a progress circle for the next one. You use
157
- the resolve function, this time passing a key. As mentioned before keys are rendered in sorted order, not in
162
+ the resolve function, this time passing a key. As mentioned before keys are rendered in sorted order, not in
158
163
the order you call the resolve function - this enables out of order rendering.
159
164
160
- Keys start at 0 - this will always have the fallback or null. You can overwrite it at any time.
165
+ Keys start at 0 - this will always have the fallback or null. You can overwrite it at any time.
161
166
162
167
### Using your own template
163
168
164
169
You can supply your own template which can use any method it likes to render parts of your
165
- UI. It is passed the keyed object provided by resolve - however in your own templates you
166
- will probably want to use named keys to make it obvious. The resolved elements are passed in ` $parts `
170
+ UI. It is passed the keyed object provided by resolve - however in your own templates you
171
+ will probably want to use named keys to make it obvious. The resolved elements are passed in ` $parts `
167
172
168
173
You can also take advantage of the ` Slot ` component which provides an easy way to render a
169
- placeholder while your component loads. Slot takes a Skeleton parameter which is the component
170
- to render which defaults to a grey div with a height passed through from Slot. Material UI Lab Skeleton
174
+ placeholder while your component loads. Slot takes a Skeleton parameter which is the component
175
+ to render which defaults to a grey div with a height passed through from Slot. Material UI Lab Skeleton
171
176
component is an excellent, more attractive, plug in for Skeleton in Slot and you can configure it in the normal
172
177
way - or use whatever your like.
173
178
@@ -262,8 +267,8 @@ way - or use whatever your like.
262
267
263
268
### Refreshing
264
269
265
- By default the wrapped component will NOT refresh if its props change. You might
266
- want to refresh it! You can do this by passing a refresh function to your component.
270
+ By default the wrapped component will NOT refresh if its props change. You might
271
+ want to refresh it! You can do this by passing a refresh function to your component.
267
272
268
273
` ` ` jsx
269
274
const YourComponent = createAsyncComponent (function MyComponent () {
@@ -278,34 +283,31 @@ If during your async code you want to restart the whole process you can call the
278
283
passed in the props.
279
284
280
285
` ` ` jsx
281
-
282
- const ExampleComponent2 = createAsyncComponent (
283
- async function MyComponent ({resolve, restart}) {
284
- resolve (< h4> Ready< / h4> )
285
- await new Promise ((resolve ) => setTimeout (resolve, 1000 ))
286
- for (let i = 0 ; i < 101 ; i++ ) {
287
- await new Promise ((resolve ) => setTimeout (resolve, 50 ))
288
- resolve (< div style= {{width: ' 100%' , background: ' #888' }}>
289
- < div
290
- style= {{
291
- width: ` ${ i * 1 } %` ,
292
- background: ' #9f54da' ,
293
- padding: 16
294
- }}
295
- >
296
- {i}
297
- < / div>
298
- {/* Restart when clicking */ }
299
- < div onClick= {() => restart ()} style= {{cursor: ' pointer' , padding: 7 , color: ' white' }}>
300
- Click to restart
301
- < / div>
302
- < / div>
303
- )
304
- }
305
- return < h4> Done< / h4>
306
- }
307
- )
308
-
286
+ const ExampleComponent2 = createAsyncComponent (async function MyComponent ({ resolve, restart }) {
287
+ resolve (< h4> Ready< / h4> )
288
+ await new Promise ((resolve ) => setTimeout (resolve, 1000 ))
289
+ for (let i = 0 ; i < 101 ; i++ ) {
290
+ await new Promise ((resolve ) => setTimeout (resolve, 50 ))
291
+ resolve (
292
+ < div style= {{ width: ' 100%' , background: ' #888' }}>
293
+ < div
294
+ style= {{
295
+ width: ` ${ i * 1 } %` ,
296
+ background: ' #9f54da' ,
297
+ padding: 16 ,
298
+ }}
299
+ >
300
+ {i}
301
+ < / div>
302
+ {/* Restart when clicking */ }
303
+ < div onClick= {() => restart ()} style= {{ cursor: ' pointer' , padding: 7 , color: ' white' }}>
304
+ Click to restart
305
+ < / div>
306
+ < / div>
307
+ )
308
+ }
309
+ return < h4> Done< / h4>
310
+ })
309
311
` ` `
310
312
311
313
### Caching
@@ -317,27 +319,26 @@ this by passing a function to `keyFn()` that works in a similar way to the refre
317
319
This significantly improves the user experience in many cases.
318
320
319
321
` ` ` jsx
320
- const YourComponent = createAsyncComponent (function ComponentNameIsUsedInCacheKey () {
322
+ const YourComponent = createAsyncComponent (function ComponentNameIsUsedInCacheKey ({ url } ) {
321
323
...
322
324
}).keyFn (({url})=> url) // cache for this url and ComponentNameIsUsedInCacheKey
323
325
324
326
` ` `
325
- The name of the function and the key are combined to create a cache that survives unmounts
326
- etc. By default it uses a last 100 LRU function.
327
327
328
+ The name of the function and the key are combined to create a cache that survives unmount
329
+ etc. By default it uses a last 100 LRU function.
328
330
329
331
## Key components/calls
330
332
331
- * AsyncFallback - provide a fallback for compnents not yet finished
332
- * Slot - provide a template slot that can be filled as component render
333
- * createAsyncComponent - called to create your wrapped component
334
- * props.resolve(key, part) OR props.resolve(part) - render components in progress
335
- * props.restart() - restart rendering
336
-
337
- * YourComponent = createAsyncComponent(Component)
338
- * keyFn(yourFn) - used to provide a caching function for your component
339
- * refreshFn(yourFn) - used to provide a way of calculating when a refresh should occur
340
- * initializeCache(size) - initializes the LRU cache to be a particular size (default 100)
333
+ - AsyncFallback - provide a fallback for components not yet finished
334
+ - Slot - provide a template slot that can be filled as component render
335
+ - createAsyncComponent - called to create your wrapped component
336
+ - props.resolve(key, part) OR props.resolve(part) - render components in progress
337
+ - props.restart() - restart rendering
338
+ - YourComponent = createAsyncComponent(Component)
339
+ - keyFn(yourFn) - used to provide a caching function for your component
340
+ - refreshFn(yourFn) - used to provide a way of calculating when a refresh should occur
341
+ - initializeCache(size) - initializes the LRU cache to be a particular size (default 100)
341
342
342
343
## License
343
344
0 commit comments