score:2
there are libraries for this, but if you want to roll your own, you can use an intersectionobserver
, something like this:
const { usestate, useref, useeffect } = react;
const lazyimage = (imageprops) => {
const [shouldload, setshouldload] = usestate(false);
const placeholderref = useref(null);
useeffect(() => {
if (!shouldload && placeholderref.current) {
const observer = new intersectionobserver(([{ intersectionratio }]) => {
if (intersectionratio > 0) {
setshouldload(true);
}
});
observer.observe(placeholderref.current);
return () => observer.disconnect();
}
}, [shouldload, placeholderref]);
return (shouldload
? <img {...imageprops}/>
: <div classname="img-placeholder" ref={placeholderref}/>
);
};
reactdom.render(
<div classname="scroll-list">
<lazyimage src='https://i.insider.com/536a52d9ecad042e1fb1a778?width=1100&format=jpeg&auto=webp'/>
<lazyimage src='https://www.denofgeek.com/wp-content/uploads/2019/12/power-rangers-beast-morphers-season-2-scaled.jpg?fit=2560%2c1440'/>
<lazyimage src='https://i1.wp.com/www.theilluminerdi.com/wp-content/uploads/2020/02/mighty-morphin-power-rangers-reunion.jpg?resize=1200%2c640&ssl=1'/>
<lazyimage src='https://m.media-amazon.com/images/m/mv5bntfiody1nditodc1zi00mje2ltk0mzqtnjexy2i1ntu3mzdixkeyxkfqcgdeqxvynzu1nze3ntg@._v1_cr0,45,480,270_al_ux477_cr0,0,477,268_al_.jpg'/>
</div>,
document.getelementbyid('app')
);
.scroll-list > * {
margin-top: 400px;
}
.img-placeholder {
content: 'placeholder!';
width: 400px;
height: 300px;
border: 1px solid black;
background-color: silver;
}
<div id="app"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
this code is having them load as soon as the placeholder is visible on the screen, but if you want a larger detection margin, you can tweak the rootmargin
option of the intersectionobserver
so it starts loading while still slightly off screen.
score:0
map the response data to an array of "isloading" booleans, and update the callback to take the index and update the specific "isloading" boolean.
function sample() {
const [items, setitems] = usestate([]);
const [imgloading, setimgloading] = usestate([]);
useeffect(() => {
axios.get(url).then((response) => {
const { data } = response;
setitems(data);
setimgloading(data.map(() => true));
});
}, []);
return items.map((item, index) => (
<img
src={item.imageurl}
onload={() =>
setimgloading((loading) =>
loading.map((el, i) => (i === index ? false : el))
)
}
/>
));
}
score:3
i would create an image
component that would handle it's own relevant states. then inside this component, i would use intersectionobserver
api to tell if the image's container is visible on user's browser or not.
i would have isloading
and isinview
states, isloading
will be always true
until isinview
updates to true
.
and while isloading
is true
, i would use null
as src
for the image and will display the placeholder.
load only the src
when container is visible on user's browser.
function image({ src }) {
const [isloading, setisloading] = usestate(true);
const [isinview, setisinview] = usestate(false);
const root = useref(); // the container
useeffect(() => {
// sets `isinview` to true until root is visible on users browser
const observer = new intersectionobserver(onintersection, { threshold: 0 });
observer.observe(root.current);
function onintersection(entries) {
const { isintersecting } = entries[0];
if (isintersecting) { // is in view
observer.disconnect();
}
setisinview(isintersecting);
}
}, []);
function onload() {
setisloading((prev) => !prev);
}
return (
<div
ref={root}
classname={`imgwrapper` + (isloading ? " imgwrapper--isloading" : "")}
>
<div classname="imgloader" />
<img classname="img" src={isinview ? src : null} alt="" onload={onload} />
</div>
);
}
i would also have css styles that will toggle the placeholder and image's display
property.
.app {
--image-height: 150px;
--image-width: var(--image-height);
}
.imgwrapper {
margin-bottom: 10px;
}
.img {
height: var(--image-height);
width: var(--image-width);
}
.imgloader {
height: 150px;
width: 150px;
background-color: red;
}
/* container is loading, hide the img */
.imgwrapper--isloading .img {
display: none;
}
/* container not loading, display img */
.imgwrapper:not(.imgwrapper--isloading) .img {
display: block;
}
/* container not loading, hide placeholder */
.imgwrapper:not(.imgwrapper--isloading) .imgloader {
display: none;
}
now my parent component, will do the requests for all the image urls. it would also have its own isloading
state that when set true
would display its own placeholder. when the image url's request resolves, i would then map on each url to render my image
components.
export default function app() {
const [imageurls, setimageurls] = usestate([]);
const [isloading, setisloading] = usestate(true);
useeffect(() => {
fetchimages().then((response) => {
setimageurls(response);
setisloading((prev) => !prev);
});
}, []);
const images = imageurls.map((url, index) => <image key={index} src={url} />);
return <div classname="app">{isloading ? "please wait..." : images}</div>;
}
Source: stackoverflow.com
Related Query
- React: How do you lazyload image from API response?
- How to Read image data from API and render in React Component
- How can I make a request to an API based on the response from another request? React Hook "useSwr" cannot be called inside a callback
- how to populate options for a react select by fetching values from an api to be visible when you click on the select box?
- How to dispatch response data from api on action in react redux?
- How to get Image response from react canvas draw?
- How to set multiple states using one response from axios API call in React
- With React useState how do you access key values of an array returned from fetch API
- How to display an <svg> tag getting as a response from an api in React
- How to build a simple chart in React based on data from API response
- How do I pass a parameter to API request 2, which I receive from API response 1 in react
- how to fetch image from the API using react js
- How to get HTML tag from API response in React Js?
- How to initialize an interface from API response using TypeScript and React
- How to add multiple Objects to an empty array react after getting response from Api react
- How to download an image from api in react without opening it?
- How can I turn the data that is a image came from API to url to use in img tag in react Js
- How to test react image component that gets it's src attribute from a REST api
- How to fetch byte array image from api in React
- How to send image from React app to api server
- How to access payload properties from API response using axios and React
- How can I use response data from an API to call another different API request in React UseEffect?
- How to map array response coming from the api using redux in react js in react js.?
- How to set state of response from axios in react
- How can I set initial React state from API data?
- How to cache API response and use it later in react & redux?
- How do you update Formik initial values with the react context api values after an AJAX request?
- React wait for a specific response from API
- React Native How to LazyLoad image
- React Select - How to show / iterate through data from api call in option instead of hardcoding options?
More Query from same tag
- How to scroll to element of the list in other component?
- React - how to prevent re-render for child component
- 'Illegal invocation' using input setCustomValidity and TS
- How to make redux action dispatched in component unmount reach the store before previous page useEffect?
- Token based authentication using Authentication header giving 403 forbidden error
- Cannot find module using gulp and react
- React, transition group - css transitions when swapping components
- How to pass props with react-router using onClick methods
- CSP issues in a project with react router and nodejs
- React Modal I want to be able to scroll a modal when it is vertically long
- How to get value from Material UI textfield after pressing enter?
- Conditionally making a number field required with YUP in React with react-hook-form
- how to display a tree data structure in react.js
- React Js onClick inside render
- how to define this $ react JS
- How to get the name of the array in json data using ReactJs?
- How to add Style on click in React
- Warning: Failed prop type: The prop open is marked as required in Snackbar, but its value is undefined
- React renders unnecessary components
- Where is the best place to put the javascript inside React?
- How to solve @apollo modules causes problems In react project?
- React / Redux app dispatching an action inside settimeout
- Ignoring failed promises in Promoise.all
- React not re-rendering the components after the first try
- Storybook: How to annotate generic args/props types
- How to hide updated state from the URL
- React.memo is not a function in 16.13.0
- react how to properly set the state (with redux)
- Webpack - Build css not applied
- How to parse the response of fetch as JSON