import React, { useReducer, useCallback } from 'react'; import VisibilitySensor from 'react-visibility-sensor'; import { Picture } from './Picture'; import placeholderSrc from '../images/placeholder.png'; import './Image.scss'; interface State { loaded: boolean; failed: boolean; visible: boolean; spacer: string; } type Action = | { type: 'EnteredViewport' } | { type: 'Loaded' } | { type: 'Failed' }; interface Props { lazyLoad?: boolean; imagePadding?: string; desktop?: string; mobile?: string; children?: React.ReactNode; } export const Image: React.FC = props => { const initialState: State = { loaded: false, failed: false, visible: false, spacer: `${props.imagePadding}%`, }; const reducer = (state: State, action: Action): State => { switch (action.type) { case 'EnteredViewport': return { ...state, visible: true }; case 'Loaded': return { ...state, loaded: true, spacer: '0px' }; case 'Failed': return { ...state, failed: true }; } }; const [state, dispatch] = useReducer(reducer, initialState); const getImgSrc = (src: string): string => { if (props.lazyLoad && !state.visible) { return '//:0'; } else if (state.failed) { return placeholderSrc; } else { return src; } }; const handleLoad = useCallback((): void => { if (!props.lazyLoad || state.visible) { dispatch({ type: 'Loaded' }); } }, [props.lazyLoad, state.visible]); const handleError = useCallback((): void => { if (!props.lazyLoad || state.visible) { dispatch({ type: 'Failed' }); } }, [props.lazyLoad, state.visible]); return (
{props.children} visible ? dispatch({ type: 'EnteredViewport' }) : null } >
); };