Replace repetitive blurhash code with component (#14267)

This commit replaces all unnecessarily repeated code for decoding and
embedding blurhash canvases with separate component - <Blurhash>.

Under the hood Blurhash component will use effect dependent on its
props. This gives a few benefits: it will only be re-rendered whenever
the hash or width/height/dummy props update, and will not render if
canvas won't get to the final DOM, because then effect won't fire,
which prevents weird bugs like #14257.
This commit is contained in:
Sasha Sorokin
2020-07-09 18:01:30 +07:00
committed by GitHub
parent 5b7a93b02c
commit 61c07c3731
5 changed files with 102 additions and 125 deletions

View File

@ -7,7 +7,7 @@ import punycode from 'punycode';
import classnames from 'classnames';
import Icon from 'mastodon/components/icon';
import { useBlurhash } from 'mastodon/initial_state';
import { decode } from 'blurhash';
import Blurhash from 'mastodon/components/blurhash';
import { debounce } from 'lodash';
const IDNA_PREFIX = 'xn--';
@ -93,38 +93,12 @@ export default class Card extends React.PureComponent {
componentDidMount () {
window.addEventListener('resize', this.handleResize, { passive: true });
if (this.props.card && this.props.card.get('blurhash') && this.canvas) {
this._decode();
}
}
componentWillUnmount () {
window.removeEventListener('resize', this.handleResize);
}
componentDidUpdate (prevProps) {
const { card } = this.props;
if (card.get('blurhash') && (!prevProps.card || prevProps.card.get('blurhash') !== card.get('blurhash')) && this.canvas) {
this._decode();
}
}
_decode () {
if (!useBlurhash) return;
const hash = this.props.card.get('blurhash');
const pixels = decode(hash, 32, 32);
if (pixels) {
const ctx = this.canvas.getContext('2d');
const imageData = new ImageData(pixels, 32, 32);
ctx.putImageData(imageData, 0, 0);
}
}
_setDimensions () {
const width = this.node.offsetWidth;
@ -182,10 +156,6 @@ export default class Card extends React.PureComponent {
}
}
setCanvasRef = c => {
this.canvas = c;
}
handleImageLoad = () => {
this.setState({ previewLoaded: true });
}
@ -238,7 +208,15 @@ export default class Card extends React.PureComponent {
);
let embed = '';
let canvas = <canvas width={32} height={32} ref={this.setCanvasRef} className={classnames('status-card__image-preview', { 'status-card__image-preview--hidden' : revealed && this.state.previewLoaded })} />;
let canvas = (
<Blurhash
className={classnames('status-card__image-preview', {
'status-card__image-preview--hidden': revealed && this.state.previewLoaded,
})}
hash={card.get('blurhash')}
dummy={!useBlurhash}
/>
);
let thumbnail = <img src={card.get('image')} alt='' style={{ width: horizontal ? width : null, height: horizontal ? height : null, visibility: revealed ? null : 'hidden' }} onLoad={this.handleImageLoad} className='status-card__image-image' />;
let spoilerButton = (
<button type='button' onClick={this.handleReveal} className='spoiler-button__overlay'>