From 8098404a1bea4d13e1980e8cc2e3bedfabd955b6 Mon Sep 17 00:00:00 2001 From: Christoph Purrer Date: Wed, 15 Jan 2025 14:02:39 -0800 Subject: [PATCH] [skip ci] Align logic in BaseTextInputShadowNode to determine updateStateIfNeeded with AndroidTextInputShadowNode (#48585) Summary: [Changelog] [Internal] - Align logic in BaseTextInputShadowNode to determine updateStateIfNeeded with AndroidTextInputShadowNode As a preparation for https://github.com/facebook/react-native/pull/48165 this aligns the implementation of those 2 methods Differential Revision: D68004755 --- .../textinput/BaseTextInputShadowNode.h | 29 +++++++++++++++---- .../AndroidTextInputShadowNode.cpp | 16 +++++----- 2 files changed, 31 insertions(+), 14 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h b/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h index 9bdd9748804ae4..edebec55316ce2 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/BaseTextInputShadowNode.h @@ -149,19 +149,36 @@ class BaseTextInputShadowNode : public ConcreteViewShadowNode< const auto& stateData = BaseShadowNode::getStateData(); const auto& reactTreeAttributedString = getAttributedString(layoutContext); - react_native_assert(textLayoutManager_); - if (stateData.reactTreeAttributedString.isContentEqual( - reactTreeAttributedString)) { + // Tree is often out of sync with the value of the TextInput. + // This is by design - don't change the value of the TextInput in the State, + // and therefore in the host platform, unless the tree itself changes. + if (stateData.reactTreeAttributedString == reactTreeAttributedString) { return; } + // If props event counter is less than what we already have in state, skip + // it const auto& props = BaseShadowNode::getConcreteProps(); - TextInputState newState( + if (props.mostRecentEventCount < stateData.mostRecentEventCount) { + return; + } + + // Even if we're here and updating state, it may be only to update the + // layout manager If that is the case, make sure we don't update text: pass + // in the current attributedString unchanged, and pass in zero for the + // "event count" so no changes are applied There's no way to prevent a state + // update from flowing to the host platform, so we just ensure it's a noop + // in those cases. + auto newEventCount = stateData.reactTreeAttributedString.isContentEqual( + reactTreeAttributedString) + ? 0 + : props.mostRecentEventCount; + + BaseShadowNode::setStateData(TextInputState{ AttributedStringBox{reactTreeAttributedString}, reactTreeAttributedString, props.paragraphAttributes, - props.mostRecentEventCount); - BaseShadowNode::setStateData(std::move(newState)); + newEventCount}); } /* diff --git a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp index d0b2b5b0c54afe..671ea8f1c93633 100644 --- a/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp +++ b/packages/react-native/ReactCommon/react/renderer/components/textinput/platform/android/react/renderer/components/androidtextinput/AndroidTextInputShadowNode.cpp @@ -120,19 +120,19 @@ LayoutConstraints AndroidTextInputShadowNode::getTextConstraints( void AndroidTextInputShadowNode::updateStateIfNeeded() { ensureUnsealed(); - + const auto& stateData = getStateData(); auto reactTreeAttributedString = getAttributedString(); - const auto& state = getStateData(); // Tree is often out of sync with the value of the TextInput. // This is by design - don't change the value of the TextInput in the State, // and therefore in Java, unless the tree itself changes. - if (state.reactTreeAttributedString == reactTreeAttributedString) { + if (stateData.reactTreeAttributedString == reactTreeAttributedString) { return; } // If props event counter is less than what we already have in state, skip it - if (getConcreteProps().mostRecentEventCount < state.mostRecentEventCount) { + const auto& props = BaseShadowNode::getConcreteProps(); + if (props.mostRecentEventCount < stateData.mostRecentEventCount) { return; } @@ -141,16 +141,16 @@ void AndroidTextInputShadowNode::updateStateIfNeeded() { // current attributedString unchanged, and pass in zero for the "event count" // so no changes are applied There's no way to prevent a state update from // flowing to Java, so we just ensure it's a noop in those cases. - auto newEventCount = - state.reactTreeAttributedString.isContentEqual(reactTreeAttributedString) + auto newEventCount = stateData.reactTreeAttributedString.isContentEqual( + reactTreeAttributedString) ? 0 - : getConcreteProps().mostRecentEventCount; + : props.mostRecentEventCount; auto newAttributedString = getMostRecentAttributedString(); setStateData(TextInputState{ AttributedStringBox(newAttributedString), reactTreeAttributedString, - getConcreteProps().paragraphAttributes, + props.paragraphAttributes, newEventCount}); }