Skip to content

Commit

Permalink
Optimize renderItem so its memoized xiaolin#423
Browse files Browse the repository at this point in the history
Deprecate imageSet
  • Loading branch information
xiaolin committed Jul 29, 2021
1 parent b6b3ce4 commit bb7d7d0
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 79 deletions.
8 changes: 3 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,15 +79,14 @@ class MyGallery extends React.Component {
* `thumbnailWidth` - image width (html5 attribute)
* `originalClass` - custom image class
* `thumbnailClass` - custom thumbnail class
* `renderItem` - Function for custom renderer (see renderItem below)
* `renderItem` - Function for custom rendering a specific slide (see renderItem below)
* `renderThumbInner` - Function for custom thumbnail renderer (see renderThumbInner below)
* `originalAlt` - image alt
* `thumbnailAlt` - thumbnail image alt
* `originalTitle` - image title
* `thumbnailTitle` - thumbnail image title
* `thumbnailLabel` - label for thumbnail
* `description` - description for image
* `imageSet` - array of `<source>` using `<picture>` element (see [`app.js`](https://github.com/xiaolin/react-image-gallery/blob/master/example/app.js) for example)
* `srcSet` - image srcset (html5 attribute)
* `sizes` - image sizes (html5 attribute)
* `bulletClass` - extra class for the bullet of the item
Expand Down Expand Up @@ -163,12 +162,11 @@ class MyGallery extends React.Component {
}
```
* `renderItem`: Function, custom item rendering
* NOTE: Highly suggest looking into a render cache such as React.memo if you plan to override renderItem
* On a specific item `[{thumbnail: '...', renderItem: this.myRenderItem}]`
or
* As a prop passed into `ImageGallery` to completely override `_renderItem`, see source for reference
* As a prop passed into `ImageGallery` to completely override `renderItem`, see source for renderItem implementation
* `renderThumbInner`: Function, custom thumbnail rendering
* On a specific item `[{thumbnail: '...', renderThumbInner: this.myRenderThumbInner}]`
or
* As a prop passed into `ImageGallery` to completely override `_renderThumbInner`, see source for reference

* `renderLeftNav`: Function, custom left nav component
Expand Down
19 changes: 2 additions & 17 deletions example/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,29 +33,15 @@ class App extends React.Component {
thumbnail: `${PREFIX_URL}4v.jpg`,
original: `${PREFIX_URL}4v.jpg`,
embedUrl: 'https://www.youtube.com/embed/4pSzhZ76GdM?autoplay=1&showinfo=0',
description: 'Render custom slides within the gallery',
description: 'Render custom slides (such as videos)',
renderItem: this._renderVideo.bind(this)
},
{
original: `${PREFIX_URL}image_set_default.jpg`,
thumbnail: `${PREFIX_URL}image_set_thumb.jpg`,
imageSet: [
{
srcSet: `${PREFIX_URL}image_set_cropped.jpg`,
media : '(max-width: 1280px)',
},
{
srcSet: `${PREFIX_URL}image_set_default.jpg`,
media : '(min-width: 1280px)',
}
]
},
{
original: `${PREFIX_URL}1.jpg`,
thumbnail: `${PREFIX_URL}1t.jpg`,
originalClass: 'featured-slide',
thumbnailClass: 'featured-thumb',
description: 'Custom class for slides & thumbnails'
description: 'Custom class for slides & thumbnails',
},
].concat(this._getStaticImages());
}
Expand Down Expand Up @@ -186,7 +172,6 @@ class App extends React.Component {
<ImageGallery
ref={i => this._imageGallery = i}
items={this.images}
lazyLoad={false}
onClick={this._onImageClick.bind(this)}
onImageLoad={this._onImageLoad}
onSlide={this._onSlide.bind(this)}
Expand Down
80 changes: 23 additions & 57 deletions src/ImageGallery.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
string,
} from 'prop-types';
import SVG from 'src/SVG';
import Item from 'src/Item';
import SwipeWrapper from 'src/SwipeWrapper';

const screenChangeEvents = [
Expand Down Expand Up @@ -64,6 +65,7 @@ class ImageGallery extends React.Component {
this.imageGallerySlideWrapper = React.createRef();

// bindings
this.handleImageLoaded = this.handleImageLoaded.bind(this);
this.handleKeyDown = this.handleKeyDown.bind(this);
this.handleMouseDown = this.handleMouseDown.bind(this);
this.handleOnSwiped = this.handleOnSwiped.bind(this);
Expand Down Expand Up @@ -472,7 +474,6 @@ class ImageGallery extends React.Component {
getSlideItems() {
const { currentIndex } = this.state;
const {
infinite,
items,
slideOnThumbnailOver,
onClick,
Expand Down Expand Up @@ -530,7 +531,8 @@ class ImageGallery extends React.Component {

slides.push(slide);

if (showThumbnails) {
// Don't add thumbnails if there is none
if (showThumbnails && item.thumbnail) {
const igThumbnailClass = clsx(
'image-gallery-thumbnail',
thumbnailClass,
Expand Down Expand Up @@ -1215,11 +1217,11 @@ class ImageGallery extends React.Component {
return false;
}

handleImageLoaded(event, item) {
handleImageLoaded(event, original) {
const { onImageLoad } = this.props;
const imageExists = this.loadedImages[item.original];
const imageExists = this.loadedImages[original];
if (!imageExists && onImageLoad) {
this.loadedImages[item.original] = true; // prevent from call again
this.loadedImages[original] = true; // prevent from call again
// image just loaded, call onImageLoad
onImageLoad(event);
}
Expand All @@ -1229,58 +1231,22 @@ class ImageGallery extends React.Component {
const { isFullscreen } = this.state;
const { onImageError } = this.props;
const handleImageError = onImageError || this.handleImageError;
const itemSrc = isFullscreen ? (item.fullscreen || item.original) : item.original;

return (
<div>
{
item.imageSet ? (
<picture
onLoad={event => this.handleImageLoaded(event, item)}
onError={handleImageError}
>
{
item.imageSet.map((source, index) => (
<source
key={`media-${index}`}
media={source.media}
srcSet={source.srcSet}
type={source.type}
/>
))
}
<img
className="image-gallery-image"
alt={item.originalAlt}
src={itemSrc}
height={item.originalHeight}
width={item.originalWidth}
/>
</picture>
) : (
<img
className="image-gallery-image"
src={itemSrc}
alt={item.originalAlt}
srcSet={item.srcSet}
height={item.originalHeight}
width={item.originalWidth}
sizes={item.sizes}
title={item.originalTitle}
onLoad={event => this.handleImageLoaded(event, item)}
onError={handleImageError}
/>
)
}

{
item.description && (
<span className="image-gallery-description">
{item.description}
</span>
)
}
</div>
<Item
description={item.description}
fullscreen={item.fullscreen}
handleImageLoaded={this.handleImageLoaded}
isFullscreen={isFullscreen}
onImageError={handleImageError}
original={item.original}
originalAlt={item.originalAlt}
originalHeight={item.originalHeight}
originalWidth={item.originalWidth}
originalTitle={item.originalTitle}
sizes={item.sizes}
srcSet={item.srcSet}
/>
);
}

Expand Down Expand Up @@ -1428,7 +1394,7 @@ class ImageGallery extends React.Component {
<div className={igContentClass}>
{(thumbnailPosition === 'bottom' || thumbnailPosition === 'right') && slideWrapper}
{
showThumbnails && (
showThumbnails && thumbnails.length > 0 ? (
<SwipeWrapper
className={thumbnailWrapperClass}
delta={0}
Expand All @@ -1446,7 +1412,7 @@ class ImageGallery extends React.Component {
</div>
</div>
</SwipeWrapper>
)
) : null
}
{(thumbnailPosition === 'top' || thumbnailPosition === 'left') && slideWrapper}
</div>
Expand Down
74 changes: 74 additions & 0 deletions src/Item.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import React from 'react';
import { bool, func, string } from 'prop-types';

const Item = React.memo(({
description,
fullscreen, // fullscreen version of img
handleImageLoaded,
isFullscreen,
onImageError,
original,
originalAlt,
originalHeight,
originalWidth,
originalTitle,
sizes,
srcSet,
}) => {
const itemSrc = isFullscreen ? (fullscreen || original) : original;

return (
<React.Fragment>
<img
className="image-gallery-image"
src={itemSrc}
alt={originalAlt}
srcSet={srcSet}
height={originalHeight}
width={originalWidth}
sizes={sizes}
title={originalTitle}
onLoad={event => handleImageLoaded(event, original)}
onError={onImageError}
/>
{
description && (
<span className="image-gallery-description">
{description}
</span>
)
}
</React.Fragment>
);
});

Item.displayName = 'Item';

Item.propTypes = {
description: string,
fullscreen: string, // fullscreen version of img
handleImageLoaded: func.isRequired,
isFullscreen: bool,
onImageError: func.isRequired,
original: string.isRequired,
originalAlt: string,
originalHeight: string,
originalWidth: string,
originalTitle: string,
sizes: string,
srcSet: string,
};

Item.defaultProps = {
description: '',
fullscreen: '',
isFullscreen: false,
originalAlt: '',
originalHeight: '',
originalWidth: '',
originalTitle: '',
sizes: '',
srcSet: '',
};

export default Item;
Binary file removed static/image_set_cropped.jpg
Binary file not shown.
Binary file removed static/image_set_default.jpg
Binary file not shown.
Binary file removed static/image_set_thumb.jpg
Binary file not shown.

0 comments on commit bb7d7d0

Please sign in to comment.