diff --git a/src/components/Avatar.js b/src/components/Avatar.js index 687ed8d4f5c4..7aebb1d8fe68 100644 --- a/src/components/Avatar.js +++ b/src/components/Avatar.js @@ -1,4 +1,4 @@ -import React, {PureComponent} from 'react'; +import React, {useEffect, useRef, useState} from 'react'; import {View} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -60,71 +60,72 @@ const defaultProps = { name: '', }; -class Avatar extends PureComponent { - constructor(props) { - super(props); - this.state = { - imageError: false, - }; - } +function Avatar(props) { + const [imageError, setImageError] = useState(false); + const prevNetworkStatusRef = useRef(props.network.isOffline); - componentDidUpdate(prevProps) { - const isReconnecting = prevProps.network.isOffline && !this.props.network.isOffline; - if (!this.state.imageError || !isReconnecting) { + useEffect(() => { + const isReconnecting = prevNetworkStatusRef.current && !props.network.isOffline; + if (!imageError || !isReconnecting) { return; } - this.setState({imageError: false}); - } + setImageError(false); - render() { - if (!this.props.source) { - return null; - } + // We have not added the imageError as the dependency because effect is concerned with `imageError` only when the network state changes from offline -> online + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [props.network.isOffline]); - const isWorkspace = this.props.type === CONST.ICON_TYPE_WORKSPACE; - const iconSize = StyleUtils.getAvatarSize(this.props.size); - - const imageStyle = [ - StyleUtils.getAvatarStyle(this.props.size), - ...this.props.imageStyles, - StyleUtils.getAvatarBorderRadius(this.props.size, this.props.type), - ]; - - const iconStyle = [ - StyleUtils.getAvatarStyle(this.props.size), - styles.bgTransparent, - ...this.props.imageStyles, - ]; - - const iconFillColor = isWorkspace ? StyleUtils.getDefaultWorspaceAvatarColor(this.props.name).fill : this.props.fill; - const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(this.props.name) : this.props.fallbackIcon; - - return ( - - {_.isFunction(this.props.source) || this.state.imageError - ? ( - - - - ) - : ( - this.setState({imageError: true})} /> - )} - - ); + useEffect(() => { + // Used to store previous network state to compare on next render + prevNetworkStatusRef.current = props.network.isOffline; + }); + + if (!props.source) { + return null; } -} + const isWorkspace = props.type === CONST.ICON_TYPE_WORKSPACE; + const iconSize = StyleUtils.getAvatarSize(props.size); + + const imageStyle = [ + StyleUtils.getAvatarStyle(props.size), + ...props.imageStyles, + StyleUtils.getAvatarBorderRadius(props.size, props.type), + ]; + + const iconStyle = [ + StyleUtils.getAvatarStyle(props.size), + styles.bgTransparent, + ...props.imageStyles, + ]; + + const iconFillColor = isWorkspace ? StyleUtils.getDefaultWorkspaceAvatarColor(props.name).fill : props.fill; + const fallbackAvatar = isWorkspace ? ReportUtils.getDefaultWorkspaceAvatar(props.name) : props.fallbackIcon; + + return ( + + {_.isFunction(props.source) || imageError + ? ( + + + + ) + : ( + setImageError(true)} /> + )} + + ); +} Avatar.defaultProps = defaultProps; Avatar.propTypes = propTypes; export default withNetwork()(Avatar); diff --git a/src/styles/StyleUtils.js b/src/styles/StyleUtils.js index 335efcf2e423..ffd454539a26 100644 --- a/src/styles/StyleUtils.js +++ b/src/styles/StyleUtils.js @@ -116,7 +116,7 @@ function getAvatarBorderStyle(size, type) { * @param {String} [workspaceName] * @returns {Object} */ -function getDefaultWorspaceAvatarColor(workspaceName) { +function getDefaultWorkspaceAvatarColor(workspaceName) { const colorHash = ReportUtils.hashLogin(workspaceName.trim(), workspaceColorOptions.length); return workspaceColorOptions[colorHash]; @@ -980,7 +980,7 @@ export { getEmojiSuggestionItemStyle, getEmojiSuggestionContainerStyle, getColoredBackgroundStyle, - getDefaultWorspaceAvatarColor, + getDefaultWorkspaceAvatarColor, getAvatarBorderRadius, getEmojiReactionBubbleStyle, getEmojiReactionBubbleTextStyle,