diff --git a/src/hooks/useStateWithCallback.js b/src/hooks/useStateWithCallback.js new file mode 100644 index 000000000000..f8658195b01b --- /dev/null +++ b/src/hooks/useStateWithCallback.js @@ -0,0 +1,26 @@ +import {useEffect, useRef, useCallback} from 'react'; +import _ from 'underscore'; + +function useStateWithCallback(state, setState) { + const callbackRef = useRef(null); + + const enhancedSetState = useCallback( + (value, callback) => { + callbackRef.current = callback; + setState(value); + }, + [setState], + ); + + useEffect(() => { + if (!_.isFunction(callbackRef.current)) { + return; + } + callbackRef.current(state); + callbackRef.current = null; + }, [enhancedSetState, state]); + + return enhancedSetState; +} + +export default useStateWithCallback; diff --git a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js index 1c537f9b4e77..7d50a1ef8b9c 100644 --- a/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js +++ b/src/pages/home/report/ReportActionCompose/ComposerWithSuggestions.js @@ -203,7 +203,20 @@ function ComposerWithSuggestions({ debouncedUpdateFrequentlyUsedEmojis(); } - setIsCommentEmpty(!!newComment.match(/^(\s)*$/)); + const previousCommentLength = commentRef.current.length; + + setIsCommentEmpty(!!newComment.match(/^(\s)*$/), () => { + // Indicate that draft has been created. + if (previousCommentLength === 0 && newComment.length !== 0) { + Report.setReportWithDraft(reportID, true); + } + + // The draft has been deleted. + if (newComment.length === 0) { + Report.setReportWithDraft(reportID, false); + } + }); + setValue(newComment); if (commentValue !== newComment) { // Ensure emoji suggestions are hidden even when the selection is not changed (so calculateEmojiSuggestion would not be called). @@ -218,16 +231,6 @@ function ComposerWithSuggestions({ }); } - // Indicate that draft has been created. - if (commentRef.current.length === 0 && newComment.length !== 0) { - Report.setReportWithDraft(reportID, true); - } - - // The draft has been deleted. - if (newComment.length === 0) { - Report.setReportWithDraft(reportID, false); - } - commentRef.current = newComment; if (shouldDebounceSaveComment) { debouncedSaveReportComment(reportID, newComment); diff --git a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js index 46153bda15e6..f4a89a5d1349 100644 --- a/src/pages/home/report/ReportActionCompose/ReportActionCompose.js +++ b/src/pages/home/report/ReportActionCompose/ReportActionCompose.js @@ -37,6 +37,7 @@ import getModalState from '../../../../libs/getModalState'; import useWindowDimensions from '../../../../hooks/useWindowDimensions'; import * as EmojiPickerActions from '../../../../libs/actions/EmojiPickerAction'; import getDraftComment from '../../../../libs/ComposerUtils/getDraftComment'; +import useStateWithCallback from '../../../../hooks/useStateWithCallback'; const propTypes = { /** A method to call when the form is submitted */ @@ -129,6 +130,8 @@ function ReportActionCompose({ return !draftComment || !!draftComment.match(/^(\s)*$/); }); + const setIsCommentEmptyWithCallback = useStateWithCallback(isCommentEmpty, setIsCommentEmpty); + /** * Updates the visibility state of the menu */ @@ -380,7 +383,7 @@ function ReportActionCompose({ disabled={disabled} isFullComposerAvailable={isFullComposerAvailable} setIsFullComposerAvailable={setIsFullComposerAvailable} - setIsCommentEmpty={setIsCommentEmpty} + setIsCommentEmpty={setIsCommentEmptyWithCallback} submitForm={submitForm} shouldShowComposeInput={shouldShowComposeInput} onFocus={onFocus}