Convert Icon to PureComponent and fix fallback

This commit is contained in:
Melvin Valster
2019-07-27 13:33:24 +02:00
parent cfcaf996c2
commit 2fcf238446
2 changed files with 87 additions and 57 deletions
-1
View File
@@ -2,7 +2,6 @@
- [ ] Fix: Initial load `pointString` validation (make sure all talents are valid and their deps are met) - [ ] Fix: Initial load `pointString` validation (make sure all talents are valid and their deps are met)
- [ ] Fix: Navigating between talent links for same class does not trigger re-render - [ ] Fix: Navigating between talent links for same class does not trigger re-render
- [ ] Fix: Icon image fallback if not locally known
- [ ] Styling: - [ ] Styling:
- [ ] SCSS: Normalize - [ ] SCSS: Normalize
+69 -38
View File
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'
import classNames from 'classnames'
import './Icon.scss' import './Icon.scss'
import React from 'react'
import classNames from 'classnames'
interface Props { interface Props {
name?: string name?: string
@@ -11,60 +11,91 @@ interface Props {
const NOT_FOUND_ICON = 'inv_misc_questionmark' const NOT_FOUND_ICON = 'inv_misc_questionmark'
export const Icon = React.forwardRef<HTMLDivElement, Props>((props, ref) => { const makeUrl = (name: string, size: string, useFallback = false): string => {
const { if (useFallback) {
name: defaultName, return `https://wow.zamimg.com/images/wow/icons/${size}/${name}.jpg`
size = 'medium', }
golden = false, return `${process.env.PUBLIC_URL}/images/icons/${size}/${name}.jpg`
children, }
className,
...rest
} = props
const [hasLoadedImage, setLoadedImage] = useState(false)
const [fadeIn, setFadeIn] = useState(false)
const [name, setName] = useState(defaultName)
const bgSize = size !== 'small' ? 'large' : 'medium' export class Icon extends React.PureComponent<Props> {
const url = name && iconUrl(name, bgSize) static defaultProps = {
size: 'medium',
golden: false
}
img: HTMLImageElement = undefined
state = {
fadeIn: false,
url: ''
}
componentDidMount() {
this.loadImage(this.props.name)
}
componentDidUpdate(prevProps: Props) {
if (prevProps.name !== this.props.name) {
this.loadImage(this.props.name)
}
}
componentWillUnmount() {
if (this.img) {
this.img.onload = null
this.img.onerror = null
this.img.src = ''
}
}
loadImage = (icon: string, useFallback = false): void => {
this.setState({ url: '', fadeIn: false })
const bgSize = this.props.size !== 'small' ? 'large' : 'medium'
const url = icon && makeUrl(icon, bgSize, useFallback)
if (!url) return
if (this.img) {
this.img.onload = null
this.img.onerror = null
this.img.src = ''
}
const start = Date.now() const start = Date.now()
this.img = new Image()
useEffect(() => { this.img.onload = () => {
if (!url) return
const img = new Image()
img.onload = () => {
const loadTime = Date.now() - start const loadTime = Date.now() - start
if (loadTime >= 300) { this.setState({ url, fadeIn: loadTime >= 300 })
setFadeIn(true) this.img = undefined
} }
setLoadedImage(true) this.img.onerror = () => {
if (url.indexOf('wow.zamimg') === -1) {
this.loadImage(icon, true)
} else {
this.loadImage(NOT_FOUND_ICON)
} }
img.onerror = () => setName(NOT_FOUND_ICON) }
img.src = url this.img.src = url
}, [url, start]) }
render() {
const { size, golden, className, ...rest } = this.props
const { fadeIn, url } = this.state
const cn = classNames('icon', `icon--${size}`, className, { const cn = classNames('icon', `icon--${size}`, className, {
'icon--golden': golden, 'icon--golden': golden,
'icon--loaded': hasLoadedImage, 'icon--loaded': !!url,
'icon--fade-in': fadeIn, 'icon--fade-in': fadeIn,
}) })
return ( return (
<div className={cn} ref={ref} {...rest}> <div className={cn} {...rest}>
{url && {url &&
<div className="icon__bg" style={{ backgroundImage: `url(${url})` }} /> <div className="icon__bg" style={{ backgroundImage: `url(${url})` }} />
} }
<div className="icon__frame" /> <div className="icon__frame" />
{children} {this.props.children}
</div> </div>
) )
})
// TODO: Fallback is broken due to no longer using require()
const iconUrl = (name: string, size: string): string => {
try {
return `${process.env.PUBLIC_URL}/images/icons/${size}/${name}.jpg`
} catch (e) {
return `https://wow.zamimg.com/images/wow/icons/${size}/${name}.jpg`
} }
} }