From b9ce9258b411f49d7baff4712725be381843b61a Mon Sep 17 00:00:00 2001 From: Pieter De Baets Date: Fri, 6 Oct 2023 05:56:36 -0700 Subject: [PATCH] Support passing in children directly when cloning nodes (#39817) Summary: Update the UIManagerBinding interface to support the upcoming API changes in https://github.com/facebook/react/pull/27458 Changelog: [Internal] Reviewed By: rubennorte, sammy-SC Differential Revision: D49912532 --- .../renderer/uimanager/UIManagerBinding.cpp | 50 +++++++++++-------- .../react/renderer/uimanager/primitives.h | 36 ++++++++++--- 2 files changed, 57 insertions(+), 29 deletions(-) diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp index c00411b6c58d78..db79e7f47ff209 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp @@ -327,25 +327,28 @@ jsi::Value UIManagerBinding::get( }); } - // Semantic: Clones the node with *same* props and *empty* children. + // Semantic: Clones the node with *same* props and *given* children. if (methodName == "cloneNodeWithNewChildren") { - auto paramCount = 1; + auto paramCount = 2; return jsi::Function::createFromHostFunction( runtime, name, paramCount, - [uiManager, methodName, paramCount]( + [uiManager, methodName]( jsi::Runtime& runtime, const jsi::Value& /*thisValue*/, const jsi::Value* arguments, size_t count) -> jsi::Value { - validateArgumentCount(runtime, methodName, paramCount, count); + // TODO: re-enable when passChildrenWhenCloningPersistedNodes is + // rolled out + // validateArgumentCount(runtime, methodName, paramCount, count); return valueFromShadowNode( runtime, uiManager->cloneNode( *shadowNodeFromValue(runtime, arguments[0]), - ShadowNode::emptySharedShadowNodeSharedList())); + count > 1 ? shadowNodeListFromValue(runtime, arguments[1]) + : ShadowNode::emptySharedShadowNodeSharedList())); }); } @@ -363,7 +366,7 @@ jsi::Value UIManagerBinding::get( size_t count) -> jsi::Value { validateArgumentCount(runtime, methodName, paramCount, count); - const auto& rawProps = RawProps(runtime, arguments[1]); + RawProps rawProps(runtime, arguments[1]); return valueFromShadowNode( runtime, uiManager->cloneNode( @@ -373,26 +376,31 @@ jsi::Value UIManagerBinding::get( }); } - // Semantic: Clones the node with *given* props and *empty* children. + // Semantic: Clones the node with *given* props and *given* children. if (methodName == "cloneNodeWithNewChildrenAndProps") { - auto paramCount = 2; + auto paramCount = 3; return jsi::Function::createFromHostFunction( runtime, name, paramCount, - [uiManager, methodName, paramCount]( + [uiManager, methodName]( jsi::Runtime& runtime, const jsi::Value& /*thisValue*/, const jsi::Value* arguments, size_t count) -> jsi::Value { - validateArgumentCount(runtime, methodName, paramCount, count); + // TODO: re-enable when passChildrenWhenCloningPersistedNodes is + // rolled out + // validateArgumentCount(runtime, methodName, paramCount, count); - const auto& rawProps = RawProps(runtime, arguments[1]); + bool hasChildrenArg = count == 3; + RawProps rawProps(runtime, arguments[hasChildrenArg ? 2 : 1]); return valueFromShadowNode( runtime, uiManager->cloneNode( *shadowNodeFromValue(runtime, arguments[0]), - ShadowNode::emptySharedShadowNodeSharedList(), + hasChildrenArg + ? shadowNodeListFromValue(runtime, arguments[1]) + : ShadowNode::emptySharedShadowNodeSharedList(), &rawProps)); }); } @@ -417,6 +425,7 @@ jsi::Value UIManagerBinding::get( }); } + // TODO: remove when passChildrenWhenCloningPersistedNodes is rolled out if (methodName == "createChildSet") { return jsi::Function::createFromHostFunction( runtime, @@ -432,6 +441,7 @@ jsi::Value UIManagerBinding::get( }); } + // TODO: remove when passChildrenWhenCloningPersistedNodes is rolled out if (methodName == "appendChildToSet") { auto paramCount = 2; return jsi::Function::createFromHostFunction( @@ -475,17 +485,13 @@ jsi::Value UIManagerBinding::get( if (!uiManager->backgroundExecutor_ || (runtimeSchedulerBinding && runtimeSchedulerBinding->getIsSynchronous())) { - auto weakShadowNodeList = - weakShadowNodeListFromValue(runtime, arguments[1]); auto shadowNodeList = - shadowNodeListFromWeakList(weakShadowNodeList); - if (shadowNodeList) { - uiManager->completeSurface( - surfaceId, - shadowNodeList, - {/* .enableStateReconciliation = */ true, - /* .mountSynchronously = */ false}); - } + shadowNodeListFromValue(runtime, arguments[1]); + uiManager->completeSurface( + surfaceId, + shadowNodeList, + {/* .enableStateReconciliation = */ true, + /* .mountSynchronously = */ false}); } else { auto weakShadowNodeList = weakShadowNodeListFromValue(runtime, arguments[1]); diff --git a/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h b/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h index c13fe9ac38b20d..ce36f64bd5a465 100644 --- a/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h +++ b/packages/react-native/ReactCommon/react/renderer/uimanager/primitives.h @@ -86,17 +86,39 @@ inline static jsi::Value valueFromShadowNode( } } +// TODO: once we no longer need to mutate the return value (appendChildToSet) +// make this a SharedListOfShared inline static ShadowNode::UnsharedListOfShared shadowNodeListFromValue( jsi::Runtime& runtime, const jsi::Value& value) { - if (CoreFeatures::useNativeState) { - return value.getObject(runtime) - .getNativeState(runtime) - ->shadowNodeList; + // TODO: cleanup when passChildrenWhenCloningPersistedNodes is rolled out + jsi::Object object = value.asObject(runtime); + if (object.isArray(runtime)) { + auto jsArray = std::move(object).asArray(runtime); + size_t jsArrayLen = jsArray.length(runtime); + if (jsArrayLen > 0) { + auto shadowNodeArray = std::make_shared(); + shadowNodeArray->reserve(jsArrayLen); + + for (size_t i = 0; i < jsArrayLen; i++) { + shadowNodeArray->push_back( + shadowNodeFromValue(runtime, jsArray.getValueAtIndex(runtime, i))); + } + return shadowNodeArray; + } else { + // TODO: return ShadowNode::emptySharedShadowNodeSharedList() + return std::make_shared( + ShadowNode::ListOfShared({})); + ; + } } else { - return value.getObject(runtime) - .getHostObject(runtime) - ->shadowNodeList; + if (CoreFeatures::useNativeState) { + return object.getNativeState(runtime) + ->shadowNodeList; + } else { + return object.getHostObject(runtime) + ->shadowNodeList; + } } }