use hooks for RandomImage

main
Mike Fix 6 years ago committed by Michael Fix
parent 5dbed921d5
commit ac23f432bc

@ -1,5 +1,6 @@
import React from 'react' import React from 'react'
import Spinner from 'react-spinner' import Spinner from 'react-spinner'
import { useAsyncCallback } from '@dawnlabs/tacklebox'
import api from '../lib/api' import api from '../lib/api'
@ -17,108 +18,80 @@ export const downloadThumbnailImage = img => {
const getImageDownloadUrl = img => const getImageDownloadUrl = img =>
api.client.get(`/unsplash/download/${img.id}`).then(res => res.data.url) api.client.get(`/unsplash/download/${img.id}`).then(res => res.data.url)
class RandomImage extends React.Component { async function getImages() {
constructor(props) { const imageUrls = await api.client.get('/unsplash/random')
super(props) return Promise.all(imageUrls.data.map(downloadThumbnailImage))
this.state = { cacheIndex: 0, loading: false } }
this.selectImage = this.selectImage.bind(this)
this.updateCache = this.updateCache.bind(this) function RandomImage(props) {
this.getImages = this.getImages.bind(this) const { current: cache } = React.useRef([])
this.nextImage = this.nextImage.bind(this) const [cacheIndex, updateIndex] = React.useState(0)
}
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
}
const image = this.cache[this.state.cacheIndex] const [selectImage, { loading: selecting }] = useAsyncCallback(() => {
const image = cache[cacheIndex]
this.setState({ loading: true }) return getImageDownloadUrl(image)
getImageDownloadUrl(image)
.then(url => api.client.get(url, { responseType: 'blob' })) .then(url => api.client.get(url, { responseType: 'blob' }))
.then(res => res.data) .then(res => res.data)
.then(blob => this.props.onChange(blob, image)) .then(blob => props.onChange(blob, image))
.then(() => this.setState({ loading: false })) })
}
const [updateCache, { loading: updating, data: imgs }] = useAsyncCallback(getImages)
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
}
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) { React.useEffect(() => {
this.updateCache() if (imgs) {
cache.push(...imgs)
} }
} }, [imgs])
render() { const loading = updating || selecting
const photographer =
this.cache[this.state.cacheIndex] && this.cache[this.state.cacheIndex].photographer const photographer = cache[cacheIndex] && cache[cacheIndex].photographer
const bgImage = this.cache[this.state.cacheIndex] && this.cache[this.state.cacheIndex].dataURL const bgImage = cache[cacheIndex] && cache[cacheIndex].dataURL
return (
return ( <div className="random-image-container">
<div className="random-image-container"> <div className="controls">
<div className="controls"> <span role="button" tabIndex={0} disabled={loading} onClick={selectImage}>
<span role="button" tabIndex={0} onClick={this.selectImage}> Use Image
Use Image </span>
</span> <span role="button" tabIndex={0} disabled={loading} onClick={() => updateIndex(i => i + 1)}>
<span role="button" tabIndex={0} onClick={this.nextImage}> Try Another
Try Another </span>
</span>
</div>
<div className="image">{this.state.loading && <Spinner />}</div>
{photographer && <PhotoCredit photographer={photographer} />}
<style jsx>
{`
.image {
width: 100%;
height: 140px;
background: url(${bgImage});
background-size: cover;
background-repeat: no-repeat;
margin-bottom: 4px;
}
.controls {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
span {
opacity: ${this.state.loading ? 0.5 : 1};
cursor: ${this.state.loading ? 'not-allowed' : 'pointer'};
user-select: none;
}
`}
</style>
</div> </div>
) <div className="image">{loading && <Spinner />}</div>
} {photographer && <PhotoCredit photographer={photographer} />}
<style jsx>
{`
.image {
width: 100%;
height: 140px;
background: url(${bgImage});
background-size: cover;
background-repeat: no-repeat;
margin-bottom: 4px;
}
.controls {
display: flex;
justify-content: space-between;
margin-bottom: 4px;
}
span {
opacity: ${loading ? 0.5 : 1};
cursor: ${loading ? 'not-allowed' : 'pointer'};
user-select: none;
}
`}
</style>
</div>
)
} }
export default RandomImage export default RandomImage

Loading…
Cancel
Save