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: Navigating between talent links for same class does not trigger re-render
- [ ] Fix: Icon image fallback if not locally known
- [ ] Styling:
- [ ] SCSS: Normalize
+69 -38
View File
@@ -1,6 +1,6 @@
import React, { useState, useEffect } from 'react'
import classNames from 'classnames'
import './Icon.scss'
import React from 'react'
import classNames from 'classnames'
interface Props {
name?: string
@@ -11,60 +11,91 @@ interface Props {
const NOT_FOUND_ICON = 'inv_misc_questionmark'
export const Icon = React.forwardRef<HTMLDivElement, Props>((props, ref) => {
const {
name: defaultName,
size = 'medium',
golden = false,
children,
className,
...rest
} = props
const [hasLoadedImage, setLoadedImage] = useState(false)
const [fadeIn, setFadeIn] = useState(false)
const [name, setName] = useState(defaultName)
const makeUrl = (name: string, size: string, useFallback = false): string => {
if (useFallback) {
return `https://wow.zamimg.com/images/wow/icons/${size}/${name}.jpg`
}
return `${process.env.PUBLIC_URL}/images/icons/${size}/${name}.jpg`
}
const bgSize = size !== 'small' ? 'large' : 'medium'
const url = name && iconUrl(name, bgSize)
export class Icon extends React.PureComponent<Props> {
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()
useEffect(() => {
if (!url) return
const img = new Image()
img.onload = () => {
this.img = new Image()
this.img.onload = () => {
const loadTime = Date.now() - start
if (loadTime >= 300) {
setFadeIn(true)
this.setState({ url, fadeIn: loadTime >= 300 })
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
}, [url, start])
}
this.img.src = url
}
render() {
const { size, golden, className, ...rest } = this.props
const { fadeIn, url } = this.state
const cn = classNames('icon', `icon--${size}`, className, {
'icon--golden': golden,
'icon--loaded': hasLoadedImage,
'icon--loaded': !!url,
'icon--fade-in': fadeIn,
})
return (
<div className={cn} ref={ref} {...rest}>
<div className={cn} {...rest}>
{url &&
<div className="icon__bg" style={{ backgroundImage: `url(${url})` }} />
}
<div className="icon__frame" />
{children}
{this.props.children}
</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`
}
}