From cd2c219bfbba9e83797a82b600e935ad9fd2828a Mon Sep 17 00:00:00 2001 From: s-alves10 Date: Thu, 5 Oct 2023 20:26:38 -0500 Subject: [PATCH] migrate: OptionRow to function component --- src/components/OptionRow.js | 407 +++++++++++++++++------------------- 1 file changed, 196 insertions(+), 211 deletions(-) diff --git a/src/components/OptionRow.js b/src/components/OptionRow.js index 70415ab03a13..849a002d5de8 100644 --- a/src/components/OptionRow.js +++ b/src/components/OptionRow.js @@ -1,6 +1,6 @@ import _ from 'underscore'; import lodashGet from 'lodash/get'; -import React, {Component} from 'react'; +import React, {useState, useEffect} from 'react'; import PropTypes from 'prop-types'; import {View, StyleSheet, InteractionManager} from 'react-native'; import styles from '../styles/styles'; @@ -97,231 +97,216 @@ const defaultProps = { shouldDisableRowInnerPadding: false, }; -class OptionRow extends Component { - constructor(props) { - super(props); - this.state = { - isDisabled: this.props.isDisabled, - }; - } +function OptionRow(props) { + const [isDisabled, setIsDisabled] = useState(props.isDisabled); - // It is very important to use shouldComponentUpdate here so SectionList items will not unnecessarily re-render - shouldComponentUpdate(nextProps, nextState) { - return ( - this.state.isDisabled !== nextState.isDisabled || - this.props.isDisabled !== nextProps.isDisabled || - this.props.isMultilineSupported !== nextProps.isMultilineSupported || - this.props.isSelected !== nextProps.isSelected || - this.props.shouldHaveOptionSeparator !== nextProps.shouldHaveOptionSeparator || - this.props.selectedStateButtonText !== nextProps.selectedStateButtonText || - this.props.showSelectedState !== nextProps.showSelectedState || - this.props.highlightSelected !== nextProps.highlightSelected || - this.props.showTitleTooltip !== nextProps.showTitleTooltip || - !_.isEqual(this.props.option.icons, nextProps.option.icons) || - this.props.optionIsFocused !== nextProps.optionIsFocused || - this.props.option.text !== nextProps.option.text || - this.props.option.alternateText !== nextProps.option.alternateText || - this.props.option.descriptiveText !== nextProps.option.descriptiveText || - this.props.option.brickRoadIndicator !== nextProps.option.brickRoadIndicator || - this.props.option.shouldShowSubscript !== nextProps.option.shouldShowSubscript || - this.props.option.ownerAccountID !== nextProps.option.ownerAccountID || - this.props.option.subtitle !== nextProps.option.subtitle || - this.props.option.pendingAction !== nextProps.option.pendingAction || - this.props.option.customIcon !== nextProps.option.customIcon - ); - } + useEffect(() => { + setIsDisabled(props.isDisabled); + }, [props.isDisabled]); - componentDidUpdate(prevProps) { - if (this.props.isDisabled === prevProps.isDisabled) { - return; - } + let pressableRef = null; + const textStyle = props.optionIsFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText; + const textUnreadStyle = props.boldStyle || props.option.boldStyle ? [textStyle, styles.sidebarLinkTextBold] : [textStyle]; + const displayNameStyle = StyleUtils.combineStyles(styles.optionDisplayName, textUnreadStyle, props.style, styles.pre, isDisabled ? styles.optionRowDisabled : {}); + const alternateTextStyle = StyleUtils.combineStyles( + textStyle, + styles.optionAlternateText, + styles.textLabelSupporting, + props.style, + lodashGet(props.option, 'alternateTextMaxLines', 1) === 1 ? styles.pre : styles.preWrap, + ); + const contentContainerStyles = [styles.flex1]; + const sidebarInnerRowStyle = StyleSheet.flatten([styles.chatLinkRowPressable, styles.flexGrow1, styles.optionItemAvatarNameWrapper, styles.optionRow, styles.justifyContentCenter]); + const hoveredBackgroundColor = props.hoverStyle && props.hoverStyle.backgroundColor ? props.hoverStyle.backgroundColor : props.backgroundColor; + const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor; + const isMultipleParticipant = lodashGet(props.option, 'participantsList.length', 0) > 1; + const defaultSubscriptSize = props.option.isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT; - this.setState({isDisabled: this.props.isDisabled}); + // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. + const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips( + (props.option.participantsList || (props.option.accountID ? [props.option] : [])).slice(0, 10), + isMultipleParticipant, + ); + let subscriptColor = themeColors.appBG; + if (props.optionIsFocused) { + subscriptColor = focusedBackgroundColor; } - render() { - let pressableRef = null; - const textStyle = this.props.optionIsFocused ? styles.sidebarLinkActiveText : styles.sidebarLinkText; - const textUnreadStyle = this.props.boldStyle || this.props.option.boldStyle ? [textStyle, styles.sidebarLinkTextBold] : [textStyle]; - const displayNameStyle = StyleUtils.combineStyles(styles.optionDisplayName, textUnreadStyle, this.props.style, styles.pre, this.state.isDisabled ? styles.optionRowDisabled : {}); - const alternateTextStyle = StyleUtils.combineStyles( - textStyle, - styles.optionAlternateText, - styles.textLabelSupporting, - this.props.style, - lodashGet(this.props.option, 'alternateTextMaxLines', 1) === 1 ? styles.pre : styles.preWrap, - ); - const contentContainerStyles = [styles.flex1]; - const sidebarInnerRowStyle = StyleSheet.flatten([styles.chatLinkRowPressable, styles.flexGrow1, styles.optionItemAvatarNameWrapper, styles.optionRow, styles.justifyContentCenter]); - const hoveredBackgroundColor = this.props.hoverStyle && this.props.hoverStyle.backgroundColor ? this.props.hoverStyle.backgroundColor : this.props.backgroundColor; - const focusedBackgroundColor = styles.sidebarLinkActive.backgroundColor; - const isMultipleParticipant = lodashGet(this.props.option, 'participantsList.length', 0) > 1; - const defaultSubscriptSize = this.props.option.isExpenseRequest ? CONST.AVATAR_SIZE.SMALL_NORMAL : CONST.AVATAR_SIZE.DEFAULT; - - // We only create tooltips for the first 10 users or so since some reports have hundreds of users, causing performance to degrade. - const displayNamesWithTooltips = ReportUtils.getDisplayNamesWithTooltips( - (this.props.option.participantsList || (this.props.option.accountID ? [this.props.option] : [])).slice(0, 10), - isMultipleParticipant, - ); - let subscriptColor = themeColors.appBG; - if (this.props.optionIsFocused) { - subscriptColor = focusedBackgroundColor; - } + return ( + + + {(hovered) => ( + (pressableRef = el)} + onPress={(e) => { + if (!props.onSelectRow) { + return; + } - return ( - - - {(hovered) => ( - (pressableRef = el)} - onPress={(e) => { - if (!this.props.onSelectRow) { - return; - } - - this.setState({isDisabled: true}); - if (e) { - e.preventDefault(); - } - let result = this.props.onSelectRow(this.props.option, pressableRef); - if (!(result instanceof Promise)) { - result = Promise.resolve(); - } - InteractionManager.runAfterInteractions(() => { - result.finally(() => this.setState({isDisabled: this.props.isDisabled})); - }); - }} - disabled={this.state.isDisabled} - style={[ - styles.flexRow, - styles.alignItemsCenter, - styles.justifyContentBetween, - styles.sidebarLink, - this.props.shouldDisableRowInnerPadding ? null : styles.sidebarLinkInner, - this.props.optionIsFocused ? styles.sidebarLinkActive : null, - this.props.shouldHaveOptionSeparator && styles.borderTop, - !this.props.onSelectRow && !this.props.isDisabled ? styles.cursorDefault : null, - this.props.isSelected && this.props.highlightSelected && styles.optionRowSelected, - ]} - accessibilityLabel={this.props.option.text} - accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON} - hoverDimmingValue={1} - hoverStyle={this.props.hoverStyle} - needsOffscreenAlphaCompositing={lodashGet(this.props.option, 'icons.length', 0) >= 2} - > - - - {!_.isEmpty(this.props.option.icons) && - (this.props.option.shouldShowSubscript ? ( - - ) : ( - - ))} - - { + result.finally(() => setIsDisabled(props.isDisabled)); + }); + }} + disabled={isDisabled} + style={[ + styles.flexRow, + styles.alignItemsCenter, + styles.justifyContentBetween, + styles.sidebarLink, + props.shouldDisableRowInnerPadding ? null : styles.sidebarLinkInner, + props.optionIsFocused ? styles.sidebarLinkActive : null, + props.shouldHaveOptionSeparator && styles.borderTop, + !props.onSelectRow && !props.isDisabled ? styles.cursorDefault : null, + props.isSelected && props.highlightSelected && styles.optionRowSelected, + ]} + accessibilityLabel={props.option.text} + accessibilityRole={CONST.ACCESSIBILITY_ROLE.BUTTON} + hoverDimmingValue={1} + hoverStyle={props.hoverStyle} + needsOffscreenAlphaCompositing={lodashGet(props.option, 'icons.length', 0) >= 2} + > + + + {!_.isEmpty(props.option.icons) && + (props.option.shouldShowSubscript ? ( + - {this.props.option.alternateText ? ( - - {this.props.option.alternateText} - - ) : null} - - {this.props.option.descriptiveText ? ( - - {this.props.option.descriptiveText} - + ) : ( + + ))} + + + {props.option.alternateText ? ( + + {props.option.alternateText} + ) : null} - {this.props.option.brickRoadIndicator === CONST.BRICK_ROAD_INDICATOR_STATUS.ERROR && ( - - - - )} - {this.props.showSelectedState && ( - <> - {this.props.shouldShowSelectedStateAsButton && !this.props.isSelected ? ( -