diff --git a/src/components/Image/index.js b/src/components/Image/index.js index 43baaebbd953..4b44bd30363d 100644 --- a/src/components/Image/index.js +++ b/src/components/Image/index.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useEffect, useMemo} from 'react'; import {Image as RNImage} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import lodashGet from 'lodash/get'; @@ -7,76 +7,64 @@ import ONYXKEYS from '../../ONYXKEYS'; import {defaultProps, imagePropTypes} from './imagePropTypes'; import RESIZE_MODES from './resizeModes'; -class Image extends React.Component { - componentDidMount() { - this.configureOnLoad(); - } - - componentDidUpdate(prevProps) { - if (prevProps.source === this.props.source) { - return; - } - this.configureOnLoad(); - } - +function Image(props) { + const {source: propsSource, isAuthTokenRequired, onLoad, session} = props; /** * Check if the image source is a URL - if so the `encryptedAuthToken` is appended * to the source. - * @returns {Object} - the configured image source */ - getImageSource() { - const source = this.props.source; - let imageSource = source; - if (this.props.isAuthTokenRequired) { + const source = useMemo(() => { + if (isAuthTokenRequired) { // There is currently a `react-native-web` bug preventing the authToken being passed // in the headers of the image request so the authToken is added as a query param. // On native the authToken IS passed in the image request headers - const authToken = lodashGet(this.props, 'session.encryptedAuthToken', null); - imageSource = {uri: `${source.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; + const authToken = lodashGet(session, 'encryptedAuthToken', null); + return {uri: `${propsSource.uri}?encryptedAuthToken=${encodeURIComponent(authToken)}`}; } - - return imageSource; - } + return propsSource; + }, [propsSource, isAuthTokenRequired, session]); /** * The natural image dimensions are retrieved using the updated source * and as a result the `onLoad` event needs to be manually invoked to return these dimensions */ - configureOnLoad() { + useEffect(() => { // If an onLoad callback was specified then manually call it and pass // the natural image dimensions to match the native API - if (this.props.onLoad == null) { + if (onLoad == null) { return; } - - const imageSource = this.getImageSource(); - RNImage.getSize(imageSource.uri, (width, height) => { - this.props.onLoad({nativeEvent: {width, height}}); + RNImage.getSize(source.uri, (width, height) => { + onLoad({nativeEvent: {width, height}}); }); - } + }, [onLoad, source]); - render() { - // Omit the props which the underlying RNImage won't use - const forwardedProps = _.omit(this.props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); - const source = this.getImageSource(); + // Omit the props which the underlying RNImage won't use + const forwardedProps = _.omit(props, ['source', 'onLoad', 'session', 'isAuthTokenRequired']); + + return ( + + ); +} - return ( - - ); - } +function imagePropsAreEqual(prevProps, nextProps) { + return prevProps.source === nextProps.source; } Image.propTypes = imagePropTypes; Image.defaultProps = defaultProps; -const ImageWithOnyx = withOnyx({ - session: { - key: ONYXKEYS.SESSION, - }, -})(Image); +const ImageWithOnyx = React.memo( + withOnyx({ + session: { + key: ONYXKEYS.SESSION, + }, + })(Image), + imagePropsAreEqual, +); ImageWithOnyx.resizeMode = RESIZE_MODES; export default ImageWithOnyx;