diff --git a/src/components/Composer/index.android.js b/src/components/Composer/index.android.js index 395aa6b889b0..fe8a89a2e100 100644 --- a/src/components/Composer/index.android.js +++ b/src/components/Composer/index.android.js @@ -1,4 +1,4 @@ -import React from 'react'; +import React, {useEffect, useCallback, useRef, useMemo} from 'react'; import {StyleSheet} from 'react-native'; import PropTypes from 'prop-types'; import _ from 'underscore'; @@ -63,57 +63,67 @@ const defaultProps = { style: null, }; -class Composer extends React.Component { - constructor(props) { - super(props); +function Composer({shouldClear, onClear, isDisabled, maxLines, forwardedRef, isComposerFullSize, setIsFullComposerAvailable, ...props}) { + const textInput = useRef(null); - this.state = { - propStyles: StyleSheet.flatten(this.props.style), - }; - } + /** + * Set the TextInput Ref + * @param {Element} el + */ + const setTextInputRef = useCallback((el) => { + textInput.current = el; + if (!_.isFunction(forwardedRef) || textInput.current === null) { + return; + } - componentDidMount() { // This callback prop is used by the parent component using the constructor to // get a ref to the inner textInput element e.g. if we do // this.textInput = el} /> this will not // return a ref to the component, but rather the HTML element by default - if (!this.props.forwardedRef || !_.isFunction(this.props.forwardedRef)) { - return; - } - - this.props.forwardedRef(this.textInput); - } + forwardedRef(textInput.current); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - componentDidUpdate(prevProps) { - if (prevProps.shouldClear || !this.props.shouldClear) { + useEffect(() => { + if (!shouldClear) { return; } - - this.textInput.clear(); - this.props.onClear(); - } - - render() { - return ( - (this.textInput = el)} - onContentSizeChange={(e) => ComposerUtils.updateNumberOfLines(this.props, e)} - rejectResponderTermination={false} - textAlignVertical="center" - // Setting a really high number here fixes an issue with the `maxNumberOfLines` prop on TextInput, where on Android the text input would collapse to only one line, - // when it should actually expand to the container (https://github.com/Expensify/App/issues/11694#issuecomment-1560520670) - // @Szymon20000 is working on fixing this (android-only) issue in the in the upstream PR (https://github.com/facebook/react-native/pulls?q=is%3Apr+is%3Aopen+maxNumberOfLines) - // TODO: remove this commend once upstream PR is merged - maximumNumberOfLines={this.props.isComposerFullSize ? 1000000 : this.props.maxLines} - style={this.state.propStyles} - /* eslint-disable-next-line react/jsx-props-no-spreading */ - {...this.props} - editable={!this.props.isDisabled} - /> - ); - } + textInput.current.clear(); + onClear(); + }, [shouldClear, onClear]); + + /** + * Set maximum number of lines + * @return {Number} + */ + const maximumNumberOfLines = useMemo(() => { + if (isComposerFullSize) return 1000000; + return maxLines; + }, [isComposerFullSize, maxLines]); + + const styles = useMemo(() => { + StyleSheet.flatten(props.style); + }, [props.style]); + + return ( + ComposerUtils.updateNumberOfLines({maxLines, isComposerFullSize, isDisabled, setIsFullComposerAvailable}, e)} + rejectResponderTermination={false} + textAlignVertical="center" + // Setting a really high number here fixes an issue with the `maxNumberOfLines` prop on TextInput, where on Android the text input would collapse to only one line, + // when it should actually expand to the container (https://github.com/Expensify/App/issues/11694#issuecomment-1560520670) + // @Szymon20000 is working on fixing this (android-only) issue in the in the upstream PR (https://github.com/facebook/react-native/pulls?q=is%3Apr+is%3Aopen+maxNumberOfLines) + // TODO: remove this commend once upstream PR is merged + maximumNumberOfLines={maximumNumberOfLines} + style={styles} + /* eslint-disable-next-line react/jsx-props-no-spreading */ + {...props} + editable={!isDisabled} + /> + ); } Composer.propTypes = propTypes;