Giter VIP home page Giter VIP logo

aljullu / react-lazy-load-image-component Goto Github PK

View Code? Open in Web Editor NEW
1.4K 8.0 110.0 1.86 MB

React Component to lazy load images and components using a HOC to track window scroll position.

Home Page: https://www.npmjs.com/package/react-lazy-load-image-component

License: MIT License

JavaScript 95.09% CSS 2.56% TypeScript 2.35%
react reactjs react-component lazy-loading lazyload lazyload-images react-lazy react-lazy-module react-performance hoc

react-lazy-load-image-component's Introduction

React Lazy Load Image Component Logo

React Lazy Load Image Component

React Component to lazy load images and other components/elements. Supports IntersectionObserver and includes a HOC to track window scroll position to improve performance.

"An easy-to-use performant solution to lazy load images in React"

Build Status Download counter License

Features

  • Includes two components (LazyLoadImage and LazyLoadComponent) and a HOC (trackWindowScroll) which adds scroll position tracking to any component you wish.
  • Handles scroll events, resize events and re-renders that might change the position of the components. And, of course, above-the-fold on initial render.
  • Placeholder by default with the same size of the image/component.
  • A custom placeholder component or image can be specified.
  • Built-in on-visible effects (blur, black and white and opacity transitions).
  • threshold is set to 100px by default and can be modified.
  • beforeLoad and onLoad events.
  • debounce and throttle included by default and configurable.
  • Uses IntersectionObserver for browsers that support it.
  • Server Side Rendering (SSR) compatible.
  • TypeScript declarations hosted on DefinitelyTyped.

Installation

# Yarn
$ yarn add react-lazy-load-image-component

# NPM
$ npm i --save react-lazy-load-image-component

LazyLoadImage usage

import React from 'react';
import { LazyLoadImage } from 'react-lazy-load-image-component';

const MyImage = ({ image }) => (
  <div>
    <LazyLoadImage
      alt={image.alt}
      height={image.height}
      src={image.src} // use normal <img> attributes as props
      width={image.width} />
    <span>{image.caption}</span>
  </div>
);

export default MyImage;

Props

Prop Type Default Description
onLoad Function Function called when the image has been loaded. This is the same function as the onLoad of an <img> which contains an event object.
afterLoad Function Deprecated, use onLoad instead. This prop is only for backward compatibility.
beforeLoad Function Function called right before the placeholder is replaced with the image element.
delayMethod String throttle Method from lodash to use to delay the scroll/resize events. It can be throttle or debounce.
delayTime Number 300 Time in ms sent to the delayMethod.
effect String Name of the effect to use. Please, read next section with an explanation on how to use them.
placeholder ReactClass <span> React element to use as a placeholder.
placeholderSrc String Image src to display while the image is not visible or loaded.
threshold Number 100 Threshold in pixels. So the image starts loading before it appears in the viewport.
useIntersectionObserver Boolean true Whether to use browser's IntersectionObserver when available.
visibleByDefault Boolean false Whether the image must be visible from the beginning.
wrapperClassName String In some occasions (for example, when using a placeholderSrc) a wrapper span tag is rendered. This prop allows setting a class to that element.
wrapperProps Object null Props that should be passed to the wrapper span when it is rendered (for example, when using placeholderSrc or effect)
... Any other image attribute

Using effects

LazyLoadImage includes several effects ready to be used, they are useful to add visual candy to your application, but are completely optional in case you don't need them or want to implement you own effect.

They rely on CSS and the corresponding CSS file must be imported:

import React from 'react';
import { LazyLoadImage } from 'react-lazy-load-image-component';
import 'react-lazy-load-image-component/src/effects/blur.css';

const MyImage = ({ image }) => (
  <LazyLoadImage
    alt={image.alt}
    effect="blur"
    wrapperProps={{
        // If you need to, you can tweak the effect transition using the wrapper style.
        style: {transitionDelay: "1s"},
    }}
    src={image.src} />
);

The current available effects are:

  • blur: renders a blurred image based on placeholderSrc and transitions to a non-blurred one when the image specified in the src is loaded.

Screenshot of the blur effect

  • black-and-white: renders a black and white image based on placeholderSrc and transitions to a colorful image when the image specified in the src is loaded.

Screenshot of the black-and-white effect

  • opacity: renders a blank space and transitions to full opacity when the image is loaded.

Screenshot of the opacity effect

All the effects have a transition duration of 0.3 seconds by default, without transition delay and the default transition timing function. All those values can be modified overriding the wrapper style as shown in the code example above.

LazyLoadComponent usage

import React from 'react';
import { LazyLoadComponent } from 'react-lazy-load-image-component';
import { ArticleContent, ArticleComments } from 'my-app';

const Article = ({ articleId }) => (
  <div>
    <ArticleContent id={articleId} />
    <LazyLoadComponent>
      <ArticleComments id={articleId} />
    </LazyLoadComponent>
  </div>
);

export default Article;

Props

Prop Type Default Description
afterLoad Function Function called after the component has been rendered.
beforeLoad Function Function called right before the component is rendered.
delayMethod String throttle Method from lodash to use to delay the scroll/resize events. It can be throttle or debounce.
delayTime Number 300 Time in ms sent to the delayMethod from lodash.
placeholder ReactClass <span> React element to use as a placeholder.
threshold Number 100 Threshold in pixels. So the component starts loading before it appears in the viewport.
useIntersectionObserver Boolean true Whether to use browser's IntersectionObserver when available.
visibleByDefault Boolean false Whether the component must be visible from the beginning.

Using trackWindowScroll HOC to improve performance

When you have many elements to lazy load in the same page, you might get poor performance because each one is listening to the scroll/resize events. In that case, it's better to wrap the deepest common parent of those components with a HOC to track those events (trackWindowScroll).

For example, if we have an App which renders a Gallery, we would wrap the Gallery component with the HOC.

import React from 'react';
import { LazyLoadImage, trackWindowScroll }
  from 'react-lazy-load-image-component';

const Gallery = ({ images, scrollPosition }) => (
  <div>
    {images.map((image) =>
      <LazyLoadImage
        key={image.key}
        alt={image.alt}
        height={image.height}
        // Make sure to pass down the scrollPosition,
        // this will be used by the component to know
        // whether it must track the scroll position or not
        scrollPosition={scrollPosition}
        src={image.src}
        width={image.width} />
    )}
  </div>
);
// Wrap Gallery with trackWindowScroll HOC so it receives
// a scrollPosition prop to pass down to the images
export default trackWindowScroll(Gallery);

You must set the prop scrollPosition to the lazy load components. This way, they will know the scroll/resize events are tracked by a parent component and will not subscribe to them.

Props

LazyLoadImage

Prop Type Default Description
scrollPosition Object Object containing x and y with the curent window scroll position. Required.
onLoad Function Function called when the image has been loaded. This is the same function as the onLoad of an <img> which contains an event object.
afterLoad Function Deprecated, use onLoad instead. This prop is only for backward compatibility.
beforeLoad Function Function called right before the image is rendered.
placeholder ReactClass <span> React element to use as a placeholder.
threshold Number 100 Threshold in pixels. So the image starts loading before it appears in the viewport.
visibleByDefault Boolean false Whether the image must be visible from the beginning.
wrapperProps Object null Props that should be passed to the wrapper span when it is rendered (for example, when using placeholderSrc or effect)
... Any other image attribute

Component wrapped with trackWindowScroll (in the example, Gallery)

Prop Type Default Description
delayMethod String throttle Method from lodash to use to delay the scroll/resize events. It can be throttle or debounce.
delayTime Number 300 Time in ms sent to the delayMethod from lodash.
useIntersectionObserver Boolean true Whether to use browser's IntersectionObserver when available.

Notice you can do the same replacing LazyLoadImage with LazyLoadComponent.

When to use visibleByDefault?

The prop visibleByDefault makes the LazyLoadImage to behave like a normal <img>. Why is it useful, then?

Imagine you are going to lazy-load an image you have already loaded in the same page. In that case, there is no need to lazy-load it because it's already stored in the cache of the user's browser. You can directly display it.

Maybe the following code snippet will make it more clear:

import React from 'react';
import { LazyLoadImage, trackWindowScroll }
  from 'react-lazy-load-image-component';

const Gallery = ({ images, scrollPosition }) => (
  <div>
    // We are loading landscape.jpg here
    <img src="/landscape.jpg" alt="Beautiful landscape" />
    {images.map((image) =>
      <LazyLoadImage
        key={image.key}
        alt={image.alt}
        scrollPosition={scrollPosition}
        src={image.src}
        // If the image we are creating here has the same src than before,
        // we can directly display it with no need to lazy-load.
        visibleByDefault={image.src === '/landscape.jpg'} />
    )}
  </div>
);

export default trackWindowScroll(Gallery);

Demos

Screenshot of the react-lazy-load-image-component in use

Common errors

All images are being loaded at once

This package loads images when they are visible in the viewport. Before an image is loaded, it occupies 0x0 pixels, so if you have a gallery of images, that means all images will be in the visible part of the page until the first ones load and start pushing down the other ones.

To fix this issue, make sure you either set a height and width props or a placeholder to your images.

Effects are not working

You need to import the effect CSS as shown in the Using effects code example.

Also, notice browsers might behave differently while images are loading. Some times, while an image is not completely loaded yet, the browser will show a white background behind it, making the effect not to be visible. This is an issue with browsers and not something that can be fixed in this package.

Warning: setState(...): Can only update a mounted or mounting component.

That warning might appear if there are two components using trackWindowScroll at the same time. Notice it's not possible to have a LazyLoadImage/LazyLoadComponent inside another LazyLoadComponent for now. Also, make sure you are passing down scrollPosition to all components wrapped inside trackWindowScroll.

react-lazy-load-image-component's People

Contributors

aljullu avatar andriiuxa avatar ashbrowning avatar bu1ka avatar crisboarna avatar ebual avatar fmmoret avatar hirokimu avatar johnsonsu avatar johnstonbl01 avatar jotacodestudio avatar jussikinnula avatar mikhailzakharov-dev avatar partykyoung avatar pierceray avatar strashkov avatar timlehner avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

react-lazy-load-image-component's Issues

Use placeholder prop with opacity effect

If I'm not mistaken the blur and black and white effects are related to the placeholderSrc, and opacity creates a blank space then transition to the loaded image.

It would be nice if I define placeholder prop, then the opacity effect could use it

Ex:
<LazyLoadImage src="some-big-image.jpg" placeholder={<div>Loading...</div>} effect="opacity" />

How to apply loader gif before loading of the image

Bug description
I have tried to put html elements/ img tag in dom before loading of the image using ur props in lazylading image component but its not working only console works nothing else

To Reproduce
const MyImage = (props) => {
const url = "https://i.giphy.com/media/xTk9ZvMnbIiIew7IpW/giphy.webp"
const spinner = () => {

    console.log('loading')
    return (
        <img src={url} alt="spinner" />
}
const afterloading = () => {
    console.log('after loading')
}

return (<div>
    <LazyLoadImage
        alt={props.alt}
        height={props.height}
        src={props.src} // use normal <img> attributes as props
        width={props.width}
        effect="blur"
        beforeLoad={spinner}
        afterLoad={afterloading}
        threshold="100" />
    <span>{props.keys}</span>
</div>
);

}

...

List any other actions needed to reproduce the issue:

  • Scroll to '...'.
  • Click on '...'.

Link to a repo where this issue can be reproduced if available:

Expected behavior
Write a clear and concise description of what you expected to happen versus what happened.

Screenshots
If applicable, add screenshots to help explain your problem.

Technical details:

  • Package version :1.4.1
  • Server Side Rendering? No
  • Device Desktop
  • Operating System : Windows,
  • Browser :Chrome, Safari

Placeholder component doesn't show

Using this code, can you tell me why the placeholder doesn't show? I've attempted using placeholder and placeholderSrc. My expected behaviour would be to see loading text on screen before the image renders

              <LazyLoadImage
                src={image.uri}
                key={index}
                alt={`${title}`}
                onClick={() => handleImageClick(image.uri)}
                effect="blur"
                placeholderSrc={<h1>loading...</h1>}
                placeholder={<h1>test</h1>}
              />

Technical details:

  • Package version ^1.4.3
  • Server Side Rendering? no
  • Device desktop
  • Operating System Mac OS
  • Browser Chrome

Support styles applied to the img after loading

Is your feature request related to a problem? Please describe.
Use case: display a grid of preview images. To avoid image distortion and support various screen sizes and layouts, one can use images that have larger natural size than the possible preview sizes. These natural images should be centered, however - otherwise, you inadvertently crop the image to its top-left region, which is undesirable (top):

gallery-details

Describe the solution you'd like
A common trick is to apply a style to the image like this (potentially in the X-direction, too):

  position: "relative",
  top: "50%",
  transform: "translateY(-50%)"
  ...

However, this should only be applied to the node. I propose to introduce loadedImageProps which are then spread to the image in getImg:

// ...
return <img onLoad={this.onImageLoad()} {...imgProps} {...loadedImageProps} />;

which can be used like

<LazyLoadImage
    loadedImageProps={{ className: classes.imagePositionHack }}
    // ...
/>

Describe alternatives you've considered
Applying the style directly to the LazyLoad component doesn't work, because the relative transform meddles with the visibility detection. A simple className for the img component could be an option, similar to material-ui allows styling of children, e.g. <LazyLoad classes={{ img: myImgClassName }} ... />.

I can send a pull request in the day.

lazyLoad doesn't work,

Bug description
Write a clear and concise description of what the bug is.
all the images loaded in the same time;

To Reproduce
Paste the code that is producing the issue

import React from "react";
import { LazyLoadImage } from 'react-lazy-load-image-component';
import uuid from 'uuid/v4';
import 'react-lazy-load-image-component/src/effects/blur.css';

import styles from './lazyImages.less';
import images from "./images";

const LazyImage = () => {
	return (
		<div className={styles.lazyImages}>
			{
				images().map((item) => {
					return <LazyLoadImage effect="blur" src={item.src} key={uuid()}/>
				})
			}
		</div>
	);
};

export default LazyImage;
const images = () => {
	return [
		{
			src: '/app/images/lazyImages/a.jpg'
	    },
		{
			src: '/app/images/lazyImages/b.jpg'
		},
		{
			src: '/app/images/lazyImages/c.jpg'
		},
		{
			src: '/app/images/lazyImages/d.jpg'
		},
		{
			src: '/app/images/lazyImages/e.jpg'
		},
	]
};
export default images;
.lazyImages{
    img{
        width: 100vw;
    }
}

image

I havn't scroll yet, all the images loaded already;

List any other actions needed to reproduce the issue:

  • Scroll to '...'.
  • Click on '...'.

Link to a repo where this issue can be reproduced if available:

Expected behavior
Write a clear and concise description of what you expected to happen versus what happened.

Screenshots
If applicable, add screenshots to help explain your problem.

Technical details:

  • Package version [1.3.2]
  • Server Side Rendering? [no]
  • Device [desktop but mobile mode]
  • Operating System [windows]
  • Browser [chrome]

React Components can't be used as placeholders

Nice library!

I'm trying to render other component as a placeholder using the placeholder prop, and I'm I tested pass a class component or stateless component but it's throwing this error
index.js:2178 uncaught at fetch Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in. Check the render method of t.

image

So how I should use this prop?

Also If I try to pass the component as placeholder={<MyComponent />}
I'm getting this

index.js:2178 uncaught at fetch TypeError: this.placeholder.getBoundingClientRect is not a function

Height and Width are required, however the documentation does not mention this.

Hi,

I have been attempting to use this package, specifically the LazyLoadImage, for a few days in my project. I had it implemented in the same was as the example under the Using trackWindowScroll HOC to improve performance section, where an array of images is mapped, however I did not specify a height and width.

With that being said, if you do not explicitly state a height and width - LazyLoadImage will not work. Without height and width, when I fetched 20 images from my API, all of the images were being fetched and loaded to the DOM at once on component render. As soon as I specified height and width, lazy load worked correctly and only images in the view port were being rendered.

I assumed height and width were not required as no where does it state that they are. I define the height and width in my css via a class name on the component, so again did not see the need for a height and width. I also noticed that some examples do not have a height or width passed into the LazyLoadImage, so again, did not think it was required.

This is either an issue with the component, or an issue with the documentation not being clear. Either way, It would be nice to specify this in the documentation :)

Component with effect has a wrapping span with custom styles predefined

Bug description
When a has an effect property defined (e.g. "opacity"), the image is wrapped with a span (where all the corresponding classes are applied (e.g. lazy-load-image-loaded)). Said span comes with some styles already defined in the component, as seen in method getWrappedLazyLoadImage() of LazyLoadImage.jsx. This raises problems when the wrapping element is expected to have its default behavior. In my case, I needed it to stay displayed as a block (as an would be), but instead it becomes an inline-block. In my case it breaks my view (see screenshot below)

To Reproduce
Create a with an effect and inspect it.

<LazyLoadImage src="test.jpg" alt="Test" effect="opacity" />

Expected behavior
The wrapping element shouldn't change how the component is rendered.

Perhaps the style for the wrapper should be defined in the CSS of each effect instead.

Screenshots
Selection_107

Technical details:

  • Package version: 1.3.2
  • Server Side Rendering? No
  • Device: any
  • Operating System: doesn't apply
  • Browser: happens with both Firefox and Chrome

Maybe it is related -or can be circumvented- if #31 is implemented

Double image download

Bug description
I use LazyLoadImage component. When I scroll page to image, and it is loading, on network tab I see that this image was loaded two times. Why does it happen and how can I fix it?

To Reproduce

<LazyLoadImage
  alt={alt}
  height={dimension}
  src={src}
  width={dimension}
/>

Technical details:

  • Package version 1.3.2
  • Server Side Rendering? Yes
  • Device Desktop/Smartphone
  • Operating System Mac OS
  • Browser Chrome

Re-Render causes effect to replay

Hi there,

I've noticed when the state is updated it causes a re-render of all child elements. If that is a LazyLoad image with an effect of opacity on it the CSS transition is re-triggered.

Is there any way to prevent this?

Thanks!

React Lazy Load Image Component not working in safari browser

I am developing a website in React.js which has a bunch of image calls.

So it was mandatory to implement lazy loading of the images so that images present in the viewport will be only called on the initial loading of the website,

I am currently using https://www.npmjs.com/package/react-lazy-load-image-component to implement lazy loading.

It is working fine in desktop browsers(including safari), android browsers but the image is not loading at all in the iPhone safari browser even after the scrolling.

This is how i use the component in my JS file,

<LazyLoadImage alt="Select a hero" src="/images/someimage.png" />

And I also use LazyLoadComponent to lazy load a section in my page and the content that is given inside this component is also not showing up in safari,

 <LazyLoadComponent> <WorkExplanation currentLanguage={this.props.currentLanguage} />
 </LazyLoadComponent>

@Aljullu Can you please help me to solve this issue?

Flicker when using placeholder image

Bug description

I am using placeholder to always display images but in low resolution. I do so because I don’t know the size of images ahead of time and use in-page anchors for navigation (this breaks when the browser can’t figure out the position of elements because images aren’t rendered). I use width="100%" and let the browser determine the height using the natural aspect ratio. This all worked perfectly before, but when using LazyLoadImage, a flicker occurs when high resolution images (that aren’t cached) are rendered (see animated gif where first cover image is cache vs the three others).

To Reproduce

<LazyLoadImage
  src={src}
  placeholder={<img src={thumbnailSrc} alt={props.alt} width="100%" />}
  scrollPosition={props.scrollPosition}
  alt={props.alt}
  width="100%"
/>

Expected behavior

No flicker

Screenshots

flicker

Technical details:

  • Package version? 1.4.1
  • Server Side Rendering? No
  • Device? Desktop (but probably both)
  • Operating System? macOS
  • Browser? Firefox, Chrome, Safari (issue present of all three)

Is it possible to use srcset?

Using the img tag's srcset attribute can improve performance massively by selectively loading different images for different devices based on resolution and pixel density. Does this library support srcSet lazy-loading, similar to lazysizes? Thanks!

image change refresh problem

When uploaded images changing, image not view refresh.
at the time of render
The picture at placeholderSrc is not shown, the old loaded picture is displayed

<LazyLoadImage src={imageUrl} width={50} alt={''} effect="black-and-white" placeholderSrc={emptyImage} delayTime={1000} />

Does anyone have any solution in this regard?

Technical details:

  • Package version [^1.4.1"]
  • Server Side Rendering? [No]
  • Device [Desktop/Smartphone]
  • Operating System [ Windows, Mac OS]
  • Browser [ Firefox, Chrome, Safari]

delaytime and delaymethod is not working

I tried to use the component like this
<LazyLoadImage
delayTime={10000}
src={'/photo.jpg'} />}

but it's not working, and when I am digging into your source code, I found out LazyLoadImage pass the prop delayTime and delayMethod to LazyLoadComponent but then they are not in use in LazyLoadComponent,

could you let me know this is a bug or this feature never works?

npm run build emits TypeError for undefined Properties

Bug description
When running npm run build an error is emitted.

$ npm run build

> [email protected] build /Users/rpierce/source/GithHub/react-lazy-load-image-component
> webpack

/Users/rpierce/source/GithHub/react-lazy-load-image-component/node_modules/webpack-cli/bin/config-yargs.js:89
				describe: optionsSchema.definitions.output.properties.path.description,
				                                          ^

TypeError: Cannot read property 'properties' of undefined
    at module.exports (/Users/rpierce/source/GithHub/react-lazy-load-image-component/node_modules/webpack-cli/bin/config-yargs.js:89:47)
    at /Users/rpierce/source/GithHub/react-lazy-load-image-component/node_modules/webpack-cli/bin/webpack.js:60:27
    at Object.<anonymous> (/Users/rpierce/source/GithHub/react-lazy-load-image-component/node_modules/webpack-cli/bin/webpack.js:515:3)
    at Module._compile (module.js:577:32)
    at Object.Module._extensions..js (module.js:586:10)
    at Module.load (module.js:494:32)
    at tryModuleLoad (module.js:453:12)
    at Function.Module._load (module.js:445:3)
    at Module.require (module.js:504:17)
    at require (internal/module.js:20:19)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] build: `webpack`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] build script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR!     /Users/rpierce/.npm/_logs/2018-12-13T04_18_14_888Z-debug.log

To Reproduce
Paste the code that is producing the issue

npm run build

List any other actions needed to reproduce the issue:

  • rm -rf node_modules && npm i

Link to a repo where this issue can be reproduced if available:

Expected behavior
npm run build succeeds without error

Technical details:

  • This seems to be a known issue with the version of webpack-cli@2
  • Upgrading to webpack-cli@3 seems to fix the issue and the build passes.

Warning: Expected server HTML to contain a matching <span> in <figure>

Bug description
When using the lib a warning is printed in the browser console.

To Reproduce
When i use this in my NextJs site, the lazy loading works ok but the browser console print a warning.
<LazyLoadImage alt={post.title.rendered} src={featuredImage} />

The warning is:
Warning: Expected server HTML to contain a matching <span> in <figure>

The problem is also described in this issue: #15

Expected behavior
Not show any warning

Technical details:

  • Server Side Rendering? [Yes]
  • Device [Desktop]
  • Operating System [GNU/Linux]
  • Browser [Firefox and Chrome at least]

Ref on images

Im trying to manipulate an image that is passed into the LazyLoadImage component via a React Ref, however I dont seem to be able to do so. The reason being is because I would like to manipulate the image, for example zoom in (increase scale) on click.

It would be great if a ref could be passed into the LazyLoadImage component, which is then put onto the image.

I have tried putting a ref onto the LazyLoadImage component its self, but this doesn't seem to work and I am unable to manipulate the actual image (for example increase its scale).

Thanks,

Lazyloading stops working beyond 5K images

Bug description
I have a use case where I have to show the user more than 100K images. My API returns images in batches of 3K images. The lazyloading works on the first batch, i.e, when I render 3K images using the lazyloadcomponent. But when I append the next batch and the batch size increases to 6K. The browser hangs and in the network tab I see that all the images are fetched instead of only the images in the viewport. I see more than 4K requests made in the network tab.

To Reproduce

class ImageGrid extends React.Component {

  render() {
      const { results, imageGridSuffix, scrollPosition } = this.props;

      const imagePlaceholder = <div style={{ width: 224, height: 224, background: "#c9c9c9" }}/>

      let divs = [];

      for (var index=0;index < results.length/3;index++) {
        const result = results[index];
        divs.push(
        <div
          key={`result-${index}`}
          className={styles.canvasRoot}
        >
          <LazyLoadComponent placeholder={imagePlaceholder} delayTime={0} scrollPosition={scrollPosition} >
            <Canvas />
          </LazyLoadComponent>
        </div>);
      }
      return divs;
    }
}

export default trackWindowScroll(ImageGrid);

Also one thing I noticed is this issue kicks in only once the total batch size of images exceed 5K. before that everything renders as expected.

Expected behavior
I expected the component to lazy load irrespective of the array size it's using.

Technical details:

  • Package version 1.3.2
  • Server Side Rendering No
  • Device Desktop
  • Operating System Mac OS
  • Browser Chrome

Default placeholder raise a warning

Hi, it looks like the default placeholder raise a warning. Is there anything that I can do to somehow fix it?

This is the implementation that I did:

const ImagePoster = props => (
  <MovieGalleryContent placeholderSrc={props.placeholder}>
    <LazyLoadImage
      src={props.src}
      style={{ width: '100%', height: '100%' }}
      onError={e => {
        e.target.onerror = null;
        e.target.src = '/static/img/clapperboard.svg';
      }}
      delayTime="0"
    />
  </MovieGalleryContent>
);

This is the warning that I got:
Expected server HTML to contain a matching <span> in <div>.

Support `overflow: scroll` containers

Currently, react-lazy-load-image-component only works with the body scroll. This issue is about adding support for overflow: scroll and similar container elements.

A <LazyLoadImage> or <LazyLoadComponent> inside a scrollable container element should only be loaded when the element becomes visible to the user and remain unloaded until then,

HOC doesn't track scroll position - `scrollPosition` is always `null`

Bug description
I'm wrapping a component in trackScrollPosition, and it's adding scrollPosition to the component props, but it's always null.

To Reproduce
See it here: https://stackblitz.com/edit/react-x6zjfs

Expected behavior
I'd expect scrollPosition to update whenever the window scrolls.

Screenshots
N/A

Technical details:

  • Package version: 1.3.2
  • Server Side Rendering? No
  • Device: Desktop
  • Operating System: Mac OS
  • Browser: Chrome

Load Animations are not working correctly

Bug description
Write a clear and concise description of what the bug is.
When the component is scrolled into view and is loading the animations are not working correctly

To Reproduce
Paste the code that is producing the issue

...Add lazy load to an image with     effect="blur"
 prop and it will not work i have tried all effects

List any other actions needed to reproduce the issue:

  • Scroll to '...'.
  • Click on '...'.

Link to a repo where this issue can be reproduced if available:

Expected behavior
Write a clear and concise description of what you expected to happen versus what happened.

Screenshots
If applicable, add screenshots to help explain your problem.

Technical details:

  • Package version [e.g. 1.2.0]
  • Server Side Rendering? [Yes/No]
  • Device [Desktop/Smartphone]
  • Operating System [e.g. Windows, Mac OS, GNU/Linux]
  • Browser [e.g. Firefox, Chrome, Safari]

Forgotten `console.log('render');` in npm build

Bug description
When package installed via npm it logging in console render.
It's placed in
react-lazy-load-image-component/src/components/LazyLoadComponent.jsx: console.log('render');

To Reproduce
npm i [email protected]
or just open console in devtools on https://www.albertjuhe.com/react-lazy-load-image-component/

Expected behavior
No debug code in build

Screenshots
image

Technical details:

  • Package version 1.3.0
  • Server Side Rendering? No
  • Device [Desktop/Smartphone]: Any
  • Operating System [e.g. Windows, Mac OS, GNU/Linux]: Any
  • Browser [e.g. Firefox, Chrome, Safari]: Any

Remove console.log("render")

Bug description
The latest on npm is still 1.3.0, so I still get this bug.

To Reproduce

npm i [email protected]
// No matching version found for [email protected]

Expected behavior
No console.log("render") in build. 1.3.2 get installed by default.

Screenshots
2019-01-21 14 17 17

Technical details:

  • Package version 1.3.0
  • Server Side Rendering? No
  • Device Desktop
  • Operating System Mac OS
  • Browser Chrome

Error window is not defined in server side rendering

Bug description
Actually, when the component is used on server side rendering, it generate a "window is not defined" error.

Expected behavior
A test for "window" can be added in order to avoid access to this variable if not defined.
To be added in both LazyLoadImage and trackWindowScroll

Technical details:

  • Server Side Rendering? Yes
  • Device Desktop/Smartphone
  • Operating System All
  • Browser All

Thx,

Roadmap

Some ideas that might or might not be implemented in the future, but good to have in a list.

  • Add a prop to load the image by default. (1aa87da)
  • Create a generic component to lazy load anything, not only images. (49f180f)
  • Allow components to listen to scroll/resize events without needing the HOC. (9833d85)
  • Add debounce/throttle. (78047bd)
  • Add some way to have a low-quality image placeholder that doesn't disappear when loading the image. Probably adding a wrapper element with background-image. (662389b)
  • Add optional CSS effects when loading the image. (784f610)
  • Use IntersectionObserver if the browser supports it. (#16#6)
  • Make it work with overflow: scroll containers (#17#28).
  • Create different Webpack environments for production/development (#18).
  • Hide the placeholder after the image is loaded (#19).

Scrollbar doesn't work when dragging over lazy loaded component.

This problem seems to be only happening on Chrome. It works well on Edge and Safari.

When grabbing the side scroll bar to go fast to a certain position in the page, the scroll bar "let's go" of the cursor, even if you still have the mouse button pressed. This happens as soon as a lazy loaded component that hasn't been loaded yet appears in view.

Here I demonstrate how dragging the scrollbar works well when moving over loaded components, but lets go as soon as it has to load one: https://www.youtube.com/watch?v=mL1vLH_3prw

Happens for both LazyLoadComponent and LazyLoadImage.
I suspected that the page changing in size when scrolling may be the issue, so I tried making sure that the elements are exactly the same size before and after the lazy loading. That didn't solve the problem.

Use IntersectionObserver

IntersectionObserver is a performant way to detect if an element is inside the viewport or not.

react-lazy-load-image-component should use that instead of some complex computations with the element position and the scroll position of the window to detect if the element is visible or not.

This must be implemented in a form that it fallbacks to the element position computations for browsers that don't support IntersectionObserver.

Images are not downloading in chrome desktop

Bug description
Images are not downloading after the page loads. If I zoom out size to 90% then they are getting downloaded. On 100% resolution of screen no image is downloaded on the page.
This issue is occuring only on my chrome desktop.

I used

for lazy loading the image on the tuples

This is the original webpage on 100% resolution
Screenshot from 2019-11-29 21-47-23

And this is the screen after I zoom out the screen resolution to 90%
Screenshot from 2019-11-29 21-48-56

Technical details:

  • Package version [e.g. 1.3.2]
  • Device [Desktop]
  • Operating System [e.g.Linux(Ubuntu)]
  • Browser [e.g. Chrome 77.0.3865.90 (Official Build) ]

Jest test warning for components with trackWindowScroll

Bug description
I test my React/Next.js app with jest and @testing-library/react and use LazyLoadImage.
If I wrap my component with trackWindowScroll test passed, but in the console, I have a warning:

Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?

    Check the render method of `r`.
        in Grid (created by r)
        in r (at Grid.test.js:12)

To Reproduce
My component

const Grid = ({ items }) => {
  return (
    <div data-testid="items-grid">
        items.map(item => (
          <LazyLoadImage
            placeholderSrc={item.lazySrc}
            src={item.src}
            alt={item.name}
            effect="blur"
            width={300}
            threshold={300}
            afterLoad={handleImageLoaded}
            onError={handleError}
          />
        ))}
    </div>
  );
};

export default trackWindowScroll(Grid);

Test

describe('CityTilesGrid', () => {
  test('should render correctly', () => {
    const { getByTestId } = render(<Grid items={mockItems} />);
    const grid = getByTestId('items-grid');

    expect(grid).toMatchSnapshot();
  });
});

Could you help me with how to get rid of this warning?

add Error image prop

Is your feature request related to a problem? Please describe.
I would like the component to display a local asset if my CDN was to fail

Describe the solution you'd like
Use a errorImage prop which is a URL to a local asset to display (instead of the native browser broken image graphic)

Describe alternatives you've considered
Expose the dom node so that we can set event handlers on it (I thought it was possible but I can't find it, please show me how if I missed that)
Expose the dom node's error and handlers

Lazy load image on `src` change

Bug description
I'm not sure if it's a bug or missing feature.
I would expect to see placeholder again after changing the src prop in <LazyLoadImage />

To Reproduce
I use this.props.imageUrl to get an url from parent component.
this.props.imageUrl changes on an external event. I think it does not matter how.

The code for reproducing the issue is:

<LazyLoadImage
                        src={this.props.imageUrl}
                        effect="opacity"
                        placeholder={<div className="loader" />}
                    />

Actions to reproduce:

  • after loading the image, change this.props.imageUrl to other URL.
    The image is loaded, but placeholder nor the beforeLoad and afterLoad functions are not called.

Expected behavior
I would expect to have:

  1. Placeholder displayed when image is loading again after changed src property.
  2. Functions beforeLoad and afterLoad called when src property was changed.

Technical details:

  • Package version [1.4.3]
  • Server Side Rendering? [No]
  • Device [Desktop]
  • Operating System [Mac OS]
  • Browser [Chrome]

IE 11 support ?

Bug description
scroll event didn't listen in IE, please support IE11 at least

To Reproduce
none
Expected behavior
none

Screenshots
none

Technical details:

  • Server Side Rendering? [No]
  • Device [Desktop]
  • Operating System [Windows]
  • Browser [IE 11]

Does this support a fallback image if the img is not loaded?

I think it should roll back to placeholderSrc if src is not found...

I can check at my end if there is no property, but if its set to black; the library before would just try to load a broken image; instead it should return something that makes the placeholderSrc render.

I used this

src={img_url ? img_url : placeholderImg}

Do not use !important in css for animations

Bug description
!important overrides my custom styles on container element

To Reproduce

.container {
background-image: url(https://someimgae.com);
}

List any other actions needed to reproduce the issue:
Add a background-image attribute to the container class

Expected behavior
I can override any style in this component

Image flickering in Sarafi browser

Bug description

I'm expecting image flickering while component switches from placeholderSrc to src image on Safari browser. It seems that in Safari placeholderSrc gets removed from the DOM before src attribute's image is applied. And it Chrome src attribute's image is applied right on top of placeholderSrc image.

To Reproduce

I'm using LazyLoadImage with params provided below.

 <LazyLoadImage
      alt={alt}
      className={'lazy-image-container'}
      src={imgSrc}
      key={id}      
      placeholderSrc={thumbnail ? thumbnail : defaultLogo}
      effect={thumbnail ? '' : 'custom'}
    />

Expected behavior

src attribute image should be applied right on top of placeholderSrc image in Safari browser.

Screenshots

Loading in Chrome (no flickering):

Loading in Safari (flickering):

Additional Details:

I might found out that flickering happens in LazyLoadImage.jsx component in const lazyLoadImage = loaded ? image : this.getLazyLoadImage(image); line. If this.state.loaded is true the lazyLoadImage value is this.getImg() function's result otherwise - this.getLazyLoadImage(image). If you won't check for loaded state, and always write to lazyLoadImage variable result of this.getLazyLoadImage(image) function the flickering will disappear.

Technical details:

  • Package version [1.3.2]
  • Server Side Rendering? [No]
  • Device [Desktop]
  • Operating System [Mac OS]
  • Browser [Safari]
  • React version [16.6.0]

Reuse the same IntersectionObserver for all components

With the change in this commit 364ce21 we stopped using window to store the IntersectionObserver and instead we store it in the component's class. That means every lazy-load image or component creates an IntersectionObserver.

It would be more efficient to use the previous approach but that was relying on the window object, which is not available in SSR.

We should use the global object available in SSR and CSR.

Unload when out of the viewport

Is your feature request related to a problem? Please describe.
I have a page with potentially 1,000 images on it. I'm worried about memory load on the browser as the user scrolls down the page. Lazily loading in will help to start with, but only if the images get unloaded when they scroll out of the viewport again.

Describe the solution you'd like
I'd like to be able to configure a LazyLoadImage to be unloaded when out of the viewport.

Describe alternatives you've considered
Pagination.

Additional context
N/A

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.