diff --git a/components/RandomImage.js b/components/RandomImage.js index c270982..2c6ed06 100644 --- a/components/RandomImage.js +++ b/components/RandomImage.js @@ -1,5 +1,6 @@ import React from 'react' import Spinner from 'react-spinner' +import { useAsyncCallback } from '@dawnlabs/tacklebox' import api from '../lib/api' @@ -17,108 +18,80 @@ export const downloadThumbnailImage = img => { const getImageDownloadUrl = img => api.client.get(`/unsplash/download/${img.id}`).then(res => res.data.url) -class RandomImage extends React.Component { - constructor(props) { - super(props) - this.state = { cacheIndex: 0, loading: false } - this.selectImage = this.selectImage.bind(this) - this.updateCache = this.updateCache.bind(this) - this.getImages = this.getImages.bind(this) - this.nextImage = this.nextImage.bind(this) - } - - cache = [] - - // fetch images in browser (we require window.FileReader) - componentDidMount() { - // clear cache when remounted - this.cache = [] - this.updateCache() - } - - async getImages() { - const imageUrls = await api.client.get('/unsplash/random') - return Promise.all(imageUrls.data.map(downloadThumbnailImage)) - } - - selectImage() { - if (this.state.loading) { - return - } +async function getImages() { + const imageUrls = await api.client.get('/unsplash/random') + return Promise.all(imageUrls.data.map(downloadThumbnailImage)) +} + +function RandomImage(props) { + const { current: cache } = React.useRef([]) + const [cacheIndex, updateIndex] = React.useState(0) - const image = this.cache[this.state.cacheIndex] + const [selectImage, { loading: selecting }] = useAsyncCallback(() => { + const image = cache[cacheIndex] - this.setState({ loading: true }) - getImageDownloadUrl(image) + return getImageDownloadUrl(image) .then(url => api.client.get(url, { responseType: 'blob' })) .then(res => res.data) - .then(blob => this.props.onChange(blob, image)) - .then(() => this.setState({ loading: false })) - } - - updateCache() { - this.setState({ loading: true }) - this.getImages() - .then(imgs => (this.cache = this.cache.concat(imgs))) - .then(() => this.setState({ loading: false })) - } - - nextImage() { - if (this.state.loading) { - return - } + .then(blob => props.onChange(blob, image)) + }) + + const [updateCache, { loading: updating, data: imgs }] = useAsyncCallback(getImages) - this.setState(state => ({ cacheIndex: state.cacheIndex + 1 })) + React.useEffect(() => { + if (cacheIndex === 0 || cacheIndex > cache.length - 2) { + updateCache() + } + }, [cacheIndex]) - if (this.state.cacheIndex > this.cache.length - 2) { - this.updateCache() + React.useEffect(() => { + if (imgs) { + cache.push(...imgs) } - } - - render() { - const photographer = - this.cache[this.state.cacheIndex] && this.cache[this.state.cacheIndex].photographer - const bgImage = this.cache[this.state.cacheIndex] && this.cache[this.state.cacheIndex].dataURL - - return ( -
-
- - Use Image - - - Try Another - -
-
{this.state.loading && }
- {photographer && } - + }, [imgs]) + + const loading = updating || selecting + + const photographer = cache[cacheIndex] && cache[cacheIndex].photographer + const bgImage = cache[cacheIndex] && cache[cacheIndex].dataURL + return ( +
+
+ + Use Image + + updateIndex(i => i + 1)}> + Try Another +
- ) - } +
{loading && }
+ {photographer && } + +
+ ) } export default RandomImage