diff --git a/src/components/ThumbnailImage.js b/src/components/ThumbnailImage.js index 970227636e46..47516164864f 100644 --- a/src/components/ThumbnailImage.js +++ b/src/components/ThumbnailImage.js @@ -1,12 +1,11 @@ import lodashClamp from 'lodash/clamp'; -import React, {PureComponent} from 'react'; -import {View, Dimensions} from 'react-native'; +import React, {useCallback, useState} from 'react'; +import {View} from 'react-native'; import PropTypes from 'prop-types'; import ImageWithSizeCalculation from './ImageWithSizeCalculation'; import styles from '../styles/styles'; import * as StyleUtils from '../styles/StyleUtils'; -import withWindowDimensions, {windowDimensionsPropTypes} from './withWindowDimensions'; -import * as DeviceCapabilities from '../libs/DeviceCapabilities'; +import useWindowDimensions from '../hooks/useWindowDimensions'; const propTypes = { /** Source URL for the preview image */ @@ -24,8 +23,6 @@ const propTypes = { /** Height of the thumbnail image */ imageHeight: PropTypes.number, - - ...windowDimensionsPropTypes, }; const defaultProps = { @@ -34,77 +31,68 @@ const defaultProps = { imageHeight: 200, }; -class ThumbnailImage extends PureComponent { - constructor(props) { - super(props); - - this.updateImageSize = this.updateImageSize.bind(this); - const {thumbnailWidth, thumbnailHeight} = this.calculateThumbnailImageSize(props.imageWidth, props.imageHeight); - this.state = { - thumbnailWidth, - thumbnailHeight, - }; - } +/** + * Compute the thumbnails width and height given original image dimensions. + * + * @param {Number} width - Width of the original image. + * @param {Number} height - Height of the original image. + * @param {Number} windowHeight - Height of the device/browser window. + * @returns {Object} - Object containing thumbnails width and height. + */ - /** - * Compute the thumbnails width and height given original image dimensions. - * - * @param {Number} width - Width of the original image. - * @param {Number} height - Height of the original image. - * @returns {Object} - Object containing thumbnails width and height. - */ - calculateThumbnailImageSize(width, height) { - if (!width || !height) { - return {}; - } +function calculateThumbnailImageSize(width, height, windowHeight) { + // Width of the thumbnail works better as a constant than it does + // a percentage of the screen width since it is relative to each screen + // Note: Clamp minimum width 40px to support touch device + let thumbnailScreenWidth = lodashClamp(width, 40, 250); + const imageHeight = height / (width / thumbnailScreenWidth); + let thumbnailScreenHeight = lodashClamp(imageHeight, 40, windowHeight * 0.4); + const aspectRatio = height / width; - // Width of the thumbnail works better as a constant than it does - // a percentage of the screen width since it is relative to each screen - // Note: Clamp minimum width 40px to support touch device - let thumbnailScreenWidth = lodashClamp(width, 40, 250); - const imageHeight = height / (width / thumbnailScreenWidth); - // On mWeb, when soft keyboard opens, window height changes, making thumbnail height inconsistent. We use screen height instead. - const screenHeight = DeviceCapabilities.canUseTouchScreen() ? Dimensions.get('screen').height : this.props.windowHeight; - let thumbnailScreenHeight = lodashClamp(imageHeight, 40, screenHeight * 0.4); - const aspectRatio = height / width; - - // If thumbnail height is greater than its width, then the image is portrait otherwise landscape. - // For portrait images, we need to adjust the width of the image to keep the aspect ratio and vice-versa. - if (thumbnailScreenHeight > thumbnailScreenWidth) { - thumbnailScreenWidth = Math.round(thumbnailScreenHeight * (1 / aspectRatio)); - } else { - thumbnailScreenHeight = Math.round(thumbnailScreenWidth * aspectRatio); - } - return {thumbnailWidth: Math.max(40, thumbnailScreenWidth), thumbnailHeight: Math.max(40, thumbnailScreenHeight)}; + // If thumbnail height is greater than its width, then the image is portrait otherwise landscape. + // For portrait images, we need to adjust the width of the image to keep the aspect ratio and vice-versa. + if (thumbnailScreenHeight > thumbnailScreenWidth) { + thumbnailScreenWidth = Math.round(thumbnailScreenHeight * (1 / aspectRatio)); + } else { + thumbnailScreenHeight = Math.round(thumbnailScreenWidth * aspectRatio); } + return {thumbnailWidth: Math.max(40, thumbnailScreenWidth), thumbnailHeight: Math.max(40, thumbnailScreenHeight)}; +} + +function ThumbnailImage(props) { + const {windowHeight} = useWindowDimensions(); + const initialDimensions = calculateThumbnailImageSize(props.imageWidth, props.imageHeight, windowHeight); + const [imageWidth, setImageWidth] = useState(initialDimensions.thumbnailWidth); + const [imageHeight, setImageHeight] = useState(initialDimensions.thumbnailHeight); /** * Update the state with the computed thumbnail sizes. * - * @param {Object} Params - width and height of the original image. - * @param {Number} Params.width - * @param {Number} Params.height + * @param {{ width: number, height: number }} Params - width and height of the original image. */ - updateImageSize({width, height}) { - const {thumbnailWidth, thumbnailHeight} = this.calculateThumbnailImageSize(width, height); - this.setState({thumbnailWidth, thumbnailHeight}); - } - render() { - return ( - - - - + const updateImageSize = useCallback( + ({width, height}) => { + const {thumbnailWidth, thumbnailHeight} = calculateThumbnailImageSize(width, height, windowHeight); + setImageWidth(thumbnailWidth); + setImageHeight(thumbnailHeight); + }, + [windowHeight], + ); + return ( + + + - ); - } + + ); } ThumbnailImage.propTypes = propTypes; ThumbnailImage.defaultProps = defaultProps; -export default withWindowDimensions(ThumbnailImage); +ThumbnailImage.displayName = 'ThumbnailImage'; +export default React.memo(ThumbnailImage);