Skip to content

Instantly share code, notes, and snippets.

@brigand
Last active June 9, 2021 03:26
Show Gist options
  • Save brigand/46daaef9149dd29f51d8c665a343d1d9 to your computer and use it in GitHub Desktop.
Save brigand/46daaef9149dd29f51d8c665a343d1d9 to your computer and use it in GitHub Desktop.
import React, { Component } from 'react';
import styled from 'styled-components';
const Figure = styled.figure`
height: 0;
margin: 0;
background-color: #efefef;
position: relative;
padding-bottom: ${props => props.ratio}%;
`;
const Img = styled.img`
width: 100%;
height: 100%;
top: 0;
position: absolute;
object-fit: contain;
opacity: ${props => props.isLoaded ? '1' : '0'};
transition: opacity .50s ease-in;
`;
// good-enough shim for this...
const idle = {
request: window.requestIdleCallback || ((fn) => setTimeout(fn, 10)),
cancel: window.cancelIdleCallback || clearTimeout,
};
class LazyImg extends Component {
constructor(props) {
super(props);
this.state = {
src: null,
value: null,
error: null,
};
}
static getDerivedStateFromProps(props, state) {
if (props.src !== state.src) {
return { src: props.src, value: null, error: null }
}
}
loadImage() {
if (this.cleanup) {
this.cleanup();
}
let idleHandle = null;
this.img = new Image();
this.img.src = this.props.src;
const src = this.img.src;
const handleLoad = () => {
idleHandle = idle.request(() => {
idleHandle = null;
this.setState({ error: null, value: { src, ratio: something } });
}, { timeout: 50 });
};
const handleError = () => {
// TODO: implement
};
img.addEventListener('load', handleLoad);
img.addEventListener('error', handleError);
// set this.cleanup to remove load/error listeners, and cancel idleHandle if needed
}
componentDidMount() {
this.loadImage();
}
componentDidUpdate(_, prevState) {
if (this.state.src !== prevState.src) {
this.loadImage();
}
}
componentWillUnmount() {
if (this.cleanup) {
this.cleanup();
}
}
render() {
if (this.state.error) {
return something // TODO
}
if (!this.state.value) {
// we're loading
}
const { src, ratio } = this.state.value;
return(
<Figure ratio={ratio}>
<Img key={src} isLoaded={true} src={src} />
</Figure>
);
}
}
export default LazyImg;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment