beekai-oss / react-simple-img Goto Github PK
View Code? Open in Web Editor NEW๐ React lazy load images with IntersectionObserver API and Priority Hints
License: MIT License
๐ React lazy load images with IntersectionObserver API and Priority Hints
License: MIT License
I tried to build a site with Gatsby v2 (React static site generator). While it worked in dev, came build time I had an error because of window
being undefined (server-side).
There was an easy workaround:
if (typeof window !== 'undefined') {
initSimpleImg({ threshold: 0.5 })
}
UPDATE: my workaround was too simple. It only works if I load the page directly, not if I load another page first and then navigate to my page with lazy loaded images. Although initSimpleImg() is called in page-2, when I load page-1 I see a console output where it's called. In my case, I use SimpleImg in a component which is used by page-2, I have to figure out (with the HOC maybe) how to handle that.
Example:
I'd like to submit a patch to support client/server detection directly in your module. Interested?
I tried a few things to get it working, but I'm not there yet (see #26).
I have a Page
(component) and another component representing a User
. The Page
will show a colleciton of User
components.
If I add the following to Page.js
import { SimpleImg, SimpleImgProvider } from 'react-simple-img'
class Page {
// ...
render () {
return this.props.users.map((user) => <User {...user} SimpleImg={SimpleImg} />)
}
}
export default SimpleImgProvider(Page, { threshold: 0.5 })
And in User.js
I use props.SimpleImg, the images are never updated, only the placeholder is shown.
I have a filter which sorts through a list of data and renders components based on the selected value. Each component has a lazy image. When the page first loads and all of the components display their images load fine. But once I use the filter the components rerender with the placeholder images without the src updating. Am I missing an easy solution for this?
Describe the bug
When I test my site using Lighthouse, either in the browser or using ex. the web.dev platform, I get a lower score in Accessibility, as well as SEO.
When I click on img
on the Failing Elements
list, it shows the exact element that fails:
By the look of things, it is the SVG placeholder.
To Reproduce
Steps to reproduce the behavior:
Audits
tabRun audits
buttonEnter a web page URL
input enter https://kepinski.me
Run audit
buttonExpected behavior
The placeholder should have an alt
attribute so that Lighthouse would not report any warnings related to that.
Screenshots
Already included them above.
Desktop (please complete the following information):
Smartphone (please complete the following information):
Additional context
Here is my image component (which uses react-simple-img
): https://github.com/xxczaki/kepinski.me/blob/37ba4c1e1a5ac2fafc494e93e38de1376ad439c8/components/me.js#L17
<SimpleImg height={300} src={this.state.uploadedUrl} />
when this.state.uploadedUrl change image not updated.
Hi,
First of all want to thank you for this great component ๐ฅ. The issue I am seeing is when using this component in a isomorphic application, I am seeing this warning in console.
Warning: Extra attributes from the server: data-from-server
Inspecting the DOM for the component reveals data-from-server=yes
. Looks like the warning comes from the React hydrate method when there as mismatch in the Server vs Client DOM tree?
NOTE: I am not initializing initSimpleImg(...)
, simply using the documented props:
<SimpleImg
animationDuration={1}
src="https://.../images/hero/hp_main_banner_960.png"
srcSet="https://.../images/hero/hp_main_banner_480.png 480w, ...."
sizes="(min-width: 480px) 480px, ...."
alt="An illustration"
/>
Is there unique steps to follow when using in isomorphic web applications?
Hi Bill,
I am having problem while using react-simple-img:
Uncaught TypeError: Cannot read property 'observer' of undefined
at SimpleImg.componentDidMount (simpleImg.js:142)
at commitLifeCycles (react-dom.development.js:15986)
at commitAllLifeCycles (react-dom.development.js:17388)
at HTMLUnknownElement.callCallback (react-dom.development.js:147)
at Object.invokeGuardedCallbackDev (react-dom.development.js:196)
at invokeGuardedCallback (react-dom.development.js:250)
at commitRoot (react-dom.development.js:17549)
at completeRoot (react-dom.development.js:19002)
at performWorkOnRoot (react-dom.development.js:18924)
at performWork (react-dom.development.js:18826)
at performSyncWork (react-dom.development.js:18799)
at interactiveUpdates$1 (react-dom.development.js:19109)
at interactiveUpdates (react-dom.development.js:2328)
at dispatchInteractiveEvent (react-dom.development.js:5134)
If I redirect from another page to the one that I am using simple-img throw this error.
This package is extremely easy to use and it works perfectly. But, there is one big problem it is not compatible with SEO. What is necessary to give support to SEO is a <noscript>
tag below the img.
Describe the solution you'd like
Add the no script tag below the img
As an example:
<img class="lazy" src="placeholder-image.jpg" data-src="image-to-lazy-load.jpg" alt="I'm an image!">
<noscript>
<img src="image-to-lazy-load.jpg" alt="I'm an image!">
</noscript>]
Additional context
Note: the ALT attribute should be also in the noscript tag
You can find more info here:
Deliver search-friendly JavaScript-powered websites
Lazy Loading Images and Video
Threshold should take in account, the lower part of the image which would the only visible part when scrolling from down.
Not sure how you could do this with one IntersectionObserver, you would need two with different roots maybe?
like this:
<SimpleImg
height={500}
placeholder="linear-gradient(rgb(30, 87, 153) 0%, rgb(125, 185, 232) 100%)"
src="your image path"
// event listener
on={() => console.log('image visible')}
once={() => console.log('image loaded')}
/>
If need to restore scroll, have to know timing that image loaded.
Describe the bug
Declaring a placeholder
using require
gives the error shown in the title.
To Reproduce
Steps to reproduce the behavior:
require('./images/cover.svg')
throws an error.src
propExpected behavior
This used to word until I updated to create-react-app@4
(which implies to remove node_modules
folder and reinstall dependencies, so maybe is related to another change). But seems that the error reproduce well in Codesandbox
Desktop (please complete the following information):
Additional context
I know that work ok just import
ing the two files, but in my case I am using several images that render dynamically so i used to pass the values like require('./images/image_' + n + '.svg')
I'm encountering a "regeneratorRuntime not found" when I'm importing the library on a create react app project. I'm currently using version 1.3.12.
Describe the bug
Number.isNaN is not supported in IE11 but is used it https://github.com/bluebill1049/react-simple-img/blob/master/src/utils/getAspectRatio.js#L13
Expected behavior
Polyfill Number.isNaN or use alternative strategy
Desktop (please complete the following information):
Hi, Blue I am using SimpleImg, but when I wanna load an image with a specific size, it loads the placeholder in a different place with a different size.
This is the wrapper.
import React from 'react';
import PropTypes from 'prop-types';
import { SimpleImg, SimpleImgProvider } from 'react-simple-img';
const LazyLoadingImage = React.memo(function LazyLoadingImage(props){
const { threshold, img, imgPlaceHolder, duration, height, width } = props;
return (
<SimpleImgProvider
config={{ threshold: [threshold || 0.5] }}
>
<SimpleImg
height={height || 500}
width={width || 500}
sizes={
`(max-width: ${width || 500}px)
(max-height: ${height || 500}px)
`
}
duration={duration || 2}
placeholder={imgPlaceHolder}
src={img}
/>
</SimpleImgProvider>
);
});
LazyLoadingImage.propTypes = {
img: PropTypes.object.isRequired,
imgPlaceHolder: PropTypes.object.isRequired,
};
export default LazyLoadingImage;
And usage
import React, { lazy, Suspense } from 'react';
import ebook from '../../imgs/e-book.png';
import ebookplaceholder from '../../imgs/e-book-placeholder-8.png';
import DivFlex from '../styled/DivFlex';
import logo2 from '../../imgs/Logo2.png';
import logo2placeholder from '../../imgs/logo2-placeholder-8.png';
const LazyLoadingImage = lazy(() => import(/* webpackChunkName: "LazyLoadingImage" */
'../Shared/LazyLoadingImage'));
const MiddleEbook = () => {
return (
<Suspense fallback={<div> Loadding ...</div>}>
<DivFlex style={{ marginTop: '15rem', border: '1px solid red'}}>
<LazyLoadingImage img={ebook} imgPlaceHolder={ebookplaceholder} />
<DivFlex>
<LazyLoadingImage img={logo2} imgPlaceHolder={logo2placeholder}
height={196} width={313}
/>
</DivFlex>
</DivFlex>
</Suspense>
);
};
export default MiddleEbook;
Error in IE:
"The object does not support the "startsWith" property or method."
How can I fix this without changing your code?
This is really odd and I wish I had some obvious explanation (so I'm asking here in the hopes that it's some corner case needing fixing).
I create a very simple image tag with SimpleImg as I'm showing below and what renders when I'm running docker locally is what is below that which shows no image because 1) it's hidden and 2) because it's hidden behind a white background.
Am I completely crazy? It works in docker production and it works when I run react in dev mode.
<SimpleImg
logConsoleError={true}
alt={speakerName}
src='/assets/images/speakers/speaker0.png'
height={200}
width={200}
/>
<div
style="position:relative;overflow:hidden;display:flex;flex-direction:column;justify-content:center;align-items:center;height:200px"
>
<noscript
><img
src="/assets/images/speakers/speaker0.png"
alt="Manoj Agarwal"/></noscript
><img
style="height:200px;width:200px;visibility:hidden"
alt="Manoj Agarwal"
src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs="
srcset=""
data-src="/assets/images/speakers/speaker0.png"
/>
<div
style="position:absolute;top:0;left:0;width:100%;height:100%;background:white;transition:0.3s opacity"
></div>
</div>
I use babel-polyfill in my app and this seems to cause the following error:
only one instance of babel-polyfill is allowed
If I remove my require(babel-polyfill) then I can get react-simple-img working, but other parts of my app break and I haven't figured out why. Is it possible to remove this dependency from react-simple-img?
How should we add crossorigin="anonymous"
?
Is your feature request related to a problem? Please describe.
Hi, there are some situations when the img url is invalid and it would great to handle those errors.
Describe the solution you'd like
Add the onerror props to
<SimpleImg onerror={} />
For example:
<img src="invalid_link" onerror="this.onerror=null;this.src='https://placeimg.com/200/300/animals';">
The above means that when the link is invalid will use a fallback img.
You can find more info about onerror here:
Inputting a default image in case the src attribute of an html is not valid?
How to handle loading images that does no exit
Hello! Awesome component. I noticed however that the animation transition doesn't seem to be working, I install react-simple-animation as well to see if that would fix it. But still got nothing.
Anyone else had this issue?
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
I would like to use react-simple image with webp as well: eg https://responsivedesign.is/articles/adding-webp-images-progressively/
Describe the solution you'd like
A clear and concise description of what you want to happen.
<picture>
<source type="image/webp"
srcset="images/worlds-300.webp 300w,
images/worlds-600.webp 600w,
images/worlds-800.webp 800w,
images/worlds.webp 1000w"
/>
<source srcset="images/worlds-300.jpg 300w,
images/worlds-600.jpg 600w,
images/worlds-800.jpg 800w,
images/worlds.jpg 1000w"
/>
<img src="images/worlds-300.jpg"
alt="The Speed of Light and the Timing of Eclipses" />
</picture>
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Add any other context or screenshots about the feature request here.
I have no issues when installing via NPM, but with Yarn I get:
$ yarn add react-simple-img@beta
yarn add v0.24.5
warning [email protected]: No license field
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
warning "[email protected]" has incorrect peer dependency "react@>=15.6.1".
warning "[email protected]" has incorrect peer dependency "react-dom @>= 15.6.1".
warning "[email protected]" has unmet peer dependency "prop-types@^1 5.6.0".
warning "[email protected]" has incorrect peer dependency "react@>= 15. 6.1".
warning "[email protected]" has incorrect peer dependency "react-dom@>= 15.6.1".
[4/4] Building fresh packages...
success Saved 0 new dependencies.
warning [email protected]: No license field
Done in 15.37s.
Which results in this error:
Error: Cannot find module 'prop-types'
Hi!
First, thanks for you create this awesome react component. I use this component in my next.js application and I got some error:
Warning: Prop
data-from-server
did not match. Server: "yes" Client: "no"
I reproduce this error on the Codesandbox, please toggle to the Console
to check this error message.
Thank you & Have a good day.
Is there a way to use the component without the wrapping div with flexbox styling and fixed height?
I'm using in the img tag width: 100%; height: auto; to make my image responsive.
Hi, in our company we have been using your library and it is working perfectly.
However, we noticed that the inline CSS is stretching the images.
We wrote the css that you need to add in order to avoid this problem.
So, instead of using this
position: absolute;
top: 0px;
left: 0px;
width: 100%;
height: 100%;
You need to add this
position: absolute;
left: -10000%;
right: -10000%;
top: -10000%;
bottom: -10000%;
margin: auto auto;
min-width: 1000%;
min-height: 1000%;
object-fit:cover;
-webkit-transform: scale(.1);
transform: scale(.1);
Then, the image looks better.
You can see a live version of the technique here: Mipon
In case that you prefer keep using the same CSS, is it possible that we can add our own css to the img?
You can check this library as a reference:
reactjs/react-tabs#148
The logic is the same, but the library allows to customize the CSS using StyledComponents.
Thanks! have a great weekend.
I have a product card with an image and two button for like and watch,
when i click these buttons the state of component changes,
this change calls render function and after that the loaded images are not visible.
whats is the problem ?
here is the code in that card for image lazy loading:
<SimpleImg
src={product.image_url}
style={{
display: 'block',
margin: 'auto',
width: '100%',
height: '100%'
}}
imgStyle={{ objectFit: 'contain', height: '100%' }}
alt={product.name1}
onError={this.onImageError}
importance={'low'}
disableAnimateCachedImg={true}
/>
Describe the bug
Images appear to be loaded over the network twice when you disable cache (via chrome dev tools). once via fetch and another via the loader.
To Reproduce
Steps to reproduce the behavior:
Expected behavior
Images should only be downloaded once
Desktop (please complete the following information):
Additional context
This is worse in my project that I'm working on., I suspect because i am not using service workers. With caching enabled, the second request for the image is retrieved from memory. Is there a way to prevent the second load with caching disabled?
First of all, thank you for building this library, I have been using it for a while now, and I just love it. My only issue is that I haven't been able to run it inside Edge (which leads me to believe that IE11 might have the same issue).
We made the following site: TrueHome (I had to disable the animation with a display: none
for edge, because the client required the change ASAP), and we can display all the images without any kind of issue in Chrome, Firefox and even inside Epiphany, (although I can see some flickering). But Edge doesn't seem to apply the animation.
I will continue testing with browserlist, polyfill and any other library related to compatibility between browsers, but do you have any idea of why this may be happening? Is this to be expected with some browsers?
Thanks in advance!!
I have the following component that I know the src is changing because if I swap <SimpleImg for <img the image changes as I would expect. It appears react-simple-img is caching the image the first time it was loaded.
import React from 'react';
import { SimpleImg } from 'react-simple-img';
import { ThemeContext, THEMELIST } from '../../contexts/ThemeContext';
function SpeakerImage({ id }) {
const { theme } = React.useContext(ThemeContext);
console.log(`SpeakerImage: id: ${id} theme: ${theme}`);
const imageUrl =
theme === THEMELIST.DARK
? `/speakers-bg-gray-500/speaker-${id}.jpg`
: `/speakers/speaker-${id}.jpg`;
return (
<>
{theme} {imageUrl}
<SimpleImg
src={imageUrl}
animationDuration='1'
width={200}
height={200}
applyAspectRatio='true'
/>
</>
);
}
export default SpeakerImage;
Hi,
I'm using both react-router
and react-simple-img
in my project.
When I'm navigating from a page to another that have <SimpleImg />
component(s) wrapped within a <SimpleImgProvider />
, it breaks (blank page).
I'm getting the following error in the console: TypeError: window.__REACT_SIMPLE_IMG__ is undefined
.
Any thoughts how to fix that? Thanks!
I would like to be able to turn off any styling that is added by react-simple-img. That is, I just want lazy loading, no animations, no class insertions. Maybe just visible on and off, but I'd prefer to even have that as an option.
Is your feature request related to a problem? Please describe.
I can see that the library is using the Intersection Observer API. Does that mean that browser support is equivalent to browsers that support Intersection Observer? Or do you use a polyfill?
Describe the solution you'd like
Add browser support list to README. This would allow developers browsing this library to instantly see what browsers are supported, and not have to look in the source code which can be time consuming.
disableAnimationAfterCache
option mentioned in the README does not exist in the source code.
How does it work?
In the global config via:
initSimpleImg({ rootMargin: '800px 800px 800px 800px'})
Nothing seems to change. Am I calling this incorrectly?
Thanks,
Dustin
Describe the bug
We're attempting to use this library with Gatsby. In SSR (server-side rendering), an empty srcSet=""
attribute is rendered on the <img
tag. This is bad because:
a) an empty srcset
attribute is invalid, and
b) This may cause the browser to block rendering and attempt to load the img
based on srcset
, completely defeating the purpose of image-lazyloading.
Here's an example of the minified output:
<img style="height:100%;width:100%;visibility:hidden;position:absolute;top:0;left:0" alt="retropie" src="data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs=" srcSet="" data-src="https://howchoo.com/media/mt/a5/yz/mta5yzzjoweg_md.jpeg" data-srcset="https://howchoo.com/media/mt/a5/yz/mta5yzzjowet.jpeg 200w, https://howchoo.com/media/mt/a5/yz/mta5yzzjoweg_xs.jpeg 360w, https://howchoo.com/media/mt/a5/yz/mta5yzzjowem.jpeg 414w, https://howchoo.com/media/mt/a5/yz/mta5yzzjoweg_md.jpeg 768w, https://howchoo.com/media/mt/a5/yz/mta5yzzjoweg.jpeg 900w, https://howchoo.com/media/mt/a5/yz/mta5yzzjowel.jpeg 1440w" sizes="(max-width: 200px) 200px, (max-width: 360px) 360px,(max-width: 414px) 414px, (max-width: 768px) 768px,(max-width: 900px) 900px, (max-width: 1440px) 1440px, 900px"/>
Note srcSet=""
above.
To Reproduce
Steps to reproduce the behavior:
gatsby build && gatsby serve
)srcSet=""
attribute on the <img>
tag.Expected behavior
I expect that attribute to not exist in the SSR HTML.
Screenshots
N/A
Desktop (please complete the following information):
Thanks for the excellent library! I'd be happy to help test a fix if needed.
Since using React.createRef
here and it's only provided from react 16.3. We should either remove this or update peerDependency
in package.json
Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
I would love to use this in typescript, but has no types!
Describe the solution you'd like
A clear and concise description of what you want to happen.
Include types as part of the build
Describe alternatives you've considered
A clear and concise description of any alternative solutions or features you've considered.
Additional context
Add any other context or screenshots about the feature request here.
I've got things working almost perfectly, but the one thing that would really add the final touch of polish for my use-case would be the ability to get the placeholder aspect ratio correct before the image loads. In my app I can't control the individual image sizes, but I do have access to the dimensions before downloading.
I tried to implement this using a dynamically sized SVG via:
const customSVG = 'data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="800" height="' + relativeHeightPixels + 'px"><rect x="0" y="0" width="800" height="' + relativeHeightPixels + 'px" fill="white" /></svg>'
Here is how I'm calling SimpleImg:
<SimpleImg className="col col-12" height={relativeHeightString} width={"100%"} src={moment.thumb_url ? moment.thumb_url : PanoMoments.assets.placeholder} />
And this works great in Chrome/Safari/Firefox, but it seems there is a bug with Edge where it never changes the opacity. I could detect the browser and not render like this for Edge, but I'd be a little worried that the opacity issue isn't as isolated as I may hope it to be. Do you see an alternative way to achieve what I'm looking for?
On iOS devices (so far only tested on an iPhone 5s running iOS 11.3) I can't seem to get any of the in-view images to load initially. It always requires a scroll (even the slightest triggers it). Have you ever seen that behavior?
This library is throwing unhandled promise rejection errors - I suspect possibly here when image loading fails: https://github.com/bluebill1049/react-simple-img/blob/4599a9b5e6d735749fa85169aa7d31d1579e6054/src/utils/fetchImage.js#L4
Unhandled promise rejection
error
โ
bubbles: false
โ
cancelBubble: false
โ
cancelable: false
โ
composed: false
โ
currentTarget: null
โ
defaultPrevented: false
โ
eventPhase: 0
โ
explicitOriginalTarget: <img src="">
โ
isTrusted: true
โ
originalTarget: <img src="">
โ
srcElement: <img src="">
โ
target: <img src="">
โ
timeStamp: 30636
โ
type: "error"
โ
<prototype>: EventPrototype { composedPath: composedPath(), stopPropagation: stopPropagation(), stopImmediatePropagation: stopImmediatePropagation(), โฆ }
es6.promise.js:110
onUnhandled/</result<
es6.promise.js:110
module.exports
_perform.js:3:12
onUnhandled/<
es6.promise.js:104
module.exports
_invoke.js:5
<anonymous>
_task.js:35
run
_task.js:21
listener
_task.js:25
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.