@@ -197,3 +197,104 @@ ReactDOM.render(
197
197
document .getElementById (' example' )
198
198
);
199
199
```
200
+
201
+ ### Masonry example with dynamically measured images
202
+
203
+ Items in the list in basic example can only be measured once, which means client has to know all the
204
+ sizes upfront before displaying. For cases when server cannot deliver such data we need to
205
+ pre-measure images. In order to preserve correct optimized layout images can only be displayed one
206
+ by one in the order they appear in the array, not in the order they are loaded.
207
+
208
+ These specifics were taken into account in a small library ` react-virtualized-image-measurer ` ,
209
+ here is an example with dynamically measured images:
210
+
211
+ ``` js
212
+ import React from " react" ;
213
+ import { render } from " react-dom" ;
214
+ import {
215
+ CellMeasurer ,
216
+ CellMeasurerCache ,
217
+ createMasonryCellPositioner ,
218
+ Masonry
219
+ } from " react-virtualized" ;
220
+ import ImageMeasurer from " react-virtualized-image-measurer" ;
221
+
222
+ // Array of images with captions
223
+ // const list = [{image: 'http://...', title: 'Foo'}];
224
+
225
+ // We need to make sure images are loaded from scratch every time for this demo
226
+ const noCacheList = list .map (item => ({
227
+ ... item,
228
+ image: item .image + " ?noCache=" + Math .random ()
229
+ }));
230
+
231
+ const columnWidth = 200 ;
232
+ const defaultHeight = 250 ;
233
+ const defaultWidth = columnWidth;
234
+
235
+ const MasonryComponent = ({ itemsWithSizes }) => {
236
+ // Default sizes help Masonry decide how many images to batch-measure
237
+ const cache = new CellMeasurerCache ({
238
+ defaultHeight,
239
+ defaultWidth,
240
+ fixedWidth: true
241
+ });
242
+
243
+ // Our masonry layout will use 3 columns with a 10px gutter between
244
+ const cellPositioner = createMasonryCellPositioner ({
245
+ cellMeasurerCache: cache,
246
+ columnCount: 3 ,
247
+ columnWidth,
248
+ spacer: 10
249
+ });
250
+
251
+ function cellRenderer ({ index, key, parent, style }) {
252
+ const { item , size } = itemsWithSizes[index];
253
+ const height = columnWidth * (size .height / size .width ) || defaultHeight;
254
+
255
+ return (
256
+ < CellMeasurer cache= {cache} index= {index} key= {key} parent= {parent}>
257
+ < div style= {style}>
258
+ < img
259
+ src= {item .image }
260
+ alt= {item .title }
261
+ style= {{
262
+ height: height,
263
+ width: columnWidth
264
+ }}
265
+ / >
266
+ < h4> {item .title }< / h4>
267
+ < / div>
268
+ < / CellMeasurer>
269
+ );
270
+ }
271
+
272
+ return (
273
+ < Masonry
274
+ cellCount= {itemsWithSizes .length }
275
+ cellMeasurerCache= {cache}
276
+ cellPositioner= {cellPositioner}
277
+ cellRenderer= {cellRenderer}
278
+ height= {600 }
279
+ width= {800 }
280
+ / >
281
+ );
282
+ };
283
+
284
+ // Render your grid
285
+ render (
286
+ < ImageMeasurer
287
+ items= {noCacheList}
288
+ image= {item => item .image }
289
+ defaultHeight= {defaultHeight}
290
+ defaultWidth= {defaultWidth}
291
+ >
292
+ {({ itemsWithSizes }) => (
293
+ < MasonryComponent itemsWithSizes= {itemsWithSizes} / >
294
+ )}
295
+ < / ImageMeasurer> ,
296
+ document .getElementById (" root" )
297
+ );
298
+ ```
299
+
300
+ Live demo: https://codesandbox.io/s/7y66p25qv6
0 commit comments