From 25d8c22baf5e110b8417b38f49af9511e58a9942 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 22 Apr 2020 15:02:19 -0700 Subject: [PATCH 1/2] Implement String ViewManager Command IDs In 0.61 Facebook added the ability to dispatch view manager commands using a string directly instead of the current indirection of getting a command ID from the view manager. This is leveraged in 0.62 in a couple places, including for Switches. UIManager overloads for string commands are added. This change impacts the C++ Microsoft.ReactNative ViewManager APIs C# and upstream view managers abstract away command IDs where they are currently left explicit in our C++ ViewManagers. Given our desire to implement built-in controls, we will need to support string commands here as well. This is made trickier with Facebook still publicly documenting grabbing command IDs from the VIewManager. Providing parallel explicit DispatchCommand functions to Microsoft.ReactNative ViewManagers would be too confusing to our users. Instead of adding parallel paths to the C++ ViewManager for commands without IDs, we remove the ID indirection entirely. Instead of internal ID mapping like we previously did with the C# ViewManagers, we now map constants to literal strings of themselves. This allows ViewManagers to accept the new form of literal string commands dispatched from JS without breaking the documented workflow of getting command IDs from the ViewManager. Eventually we should be able to remove integer only command IDs, as they are internally deprecated. Validated C# and C++ commands still work through the sample app. Validated switch behavior using the RNTester page. Fixes #4596 --- .../windows/SampleAppCPP/SampleAppCpp.vcxproj | 1 - .../CustomUserControlViewManagerCPP.cpp | 10 ++-- .../CustomUserControlViewManagerCPP.h | 4 +- .../SampleLibraryCPP/SampleLibraryCPP.vcxproj | 1 - vnext/Desktop.DLL/react-native-win32.x64.def | 2 +- vnext/Desktop.DLL/react-native-win32.x86.def | 2 +- .../Desktop.UnitTests/EmptyUIManagerModule.h | 5 +- .../AttributedViewManager.cs | 25 ++++------ .../Microsoft.ReactNative/ABIViewManager.cpp | 20 ++++---- vnext/Microsoft.ReactNative/ABIViewManager.h | 2 +- vnext/Microsoft.ReactNative/IViewManager.idl | 6 +-- vnext/ReactUWP/Views/ScrollViewManager.cpp | 50 ++++++++----------- vnext/ReactUWP/Views/ShadowNodeBase.cpp | 2 +- vnext/ReactUWP/Views/SwitchViewManager.cpp | 12 +++++ vnext/ReactUWP/Views/SwitchViewManager.h | 1 + vnext/ReactUWP/Views/ViewManagerBase.cpp | 2 +- vnext/ReactWindowsCore/IUIManager.h | 3 +- .../Modules/UIManagerModule.cpp | 10 +++- .../Modules/UIManagerModule.h | 4 +- vnext/ReactWindowsCore/ShadowNode.cpp | 2 +- vnext/ReactWindowsCore/ShadowNode.h | 2 +- vnext/include/ReactUWP/Views/ShadowNodeBase.h | 2 +- .../include/ReactUWP/Views/ViewManagerBase.h | 2 +- 23 files changed, 91 insertions(+), 79 deletions(-) diff --git a/packages/microsoft-reactnative-sampleapps/windows/SampleAppCPP/SampleAppCpp.vcxproj b/packages/microsoft-reactnative-sampleapps/windows/SampleAppCPP/SampleAppCpp.vcxproj index c18ff844d50..5ed4d7a13e9 100644 --- a/packages/microsoft-reactnative-sampleapps/windows/SampleAppCPP/SampleAppCpp.vcxproj +++ b/packages/microsoft-reactnative-sampleapps/windows/SampleAppCPP/SampleAppCpp.vcxproj @@ -41,7 +41,6 @@ $([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), 'node_modules\react-native-windows\package.json'))\node_modules\react-native-windows\ - Debug diff --git a/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.cpp b/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.cpp index 8bc8dea706e..58ce16cc054 100644 --- a/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.cpp +++ b/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.cpp @@ -105,18 +105,18 @@ void CustomUserControlViewManagerCpp::UpdateProperties( } // IViewManagerWithCommands -IMapView CustomUserControlViewManagerCpp::Commands() noexcept { - auto commands = winrt::single_threaded_map(); - commands.Insert(L"CustomCommand", 0); +IVectorView CustomUserControlViewManagerCpp::Commands() noexcept { + auto commands = winrt::single_threaded_vector(); + commands.Append(L"CustomCommand"); return commands.GetView(); } void CustomUserControlViewManagerCpp::DispatchCommand( FrameworkElement const &view, - int64_t commandId, + winrt::hstring const &commandId, IJSValueReader const &commandArgsReader) noexcept { if (auto control = view.try_as()) { - if (commandId == 0) { + if (commandId == L"CustomCommand") { std::string arg = std::to_string(winrt::unbox_value(view.Tag())); arg.append(", \""); arg.append(winrt::to_string(commandArgsReader.GetString())); diff --git a/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.h b/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.h index 8a07bb92ac4..d9e5775e011 100644 --- a/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.h +++ b/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/CustomUserControlViewManagerCPP.h @@ -38,11 +38,11 @@ struct CustomUserControlViewManagerCpp winrt::Microsoft::ReactNative::IJSValueReader const &propertyMapReader) noexcept; // IViewManagerWithCommands - winrt::Windows::Foundation::Collections::IMapView Commands() noexcept; + winrt::Windows::Foundation::Collections::IVectorView Commands() noexcept; void DispatchCommand( winrt::Windows::UI::Xaml::FrameworkElement const &view, - int64_t commandId, + winrt::hstring const &commandId, winrt::Microsoft::ReactNative::IJSValueReader const &commandArgsReader) noexcept; // IViewManagerWithExportedEventTypeConstants diff --git a/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/SampleLibraryCPP.vcxproj b/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/SampleLibraryCPP.vcxproj index 444db48e6bc..bb3b37cbd45 100644 --- a/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/SampleLibraryCPP.vcxproj +++ b/packages/microsoft-reactnative-sampleapps/windows/SampleLibraryCPP/SampleLibraryCPP.vcxproj @@ -17,7 +17,6 @@ 10.0.16299.0 - Debug diff --git a/vnext/Desktop.DLL/react-native-win32.x64.def b/vnext/Desktop.DLL/react-native-win32.x64.def index 280de54d461..253bc9d1dfa 100644 --- a/vnext/Desktop.DLL/react-native-win32.x64.def +++ b/vnext/Desktop.DLL/react-native-win32.x64.def @@ -34,7 +34,7 @@ EXPORTS ?createIUIManager@react@facebook@@YA?AV?$shared_ptr@VIUIManager@react@facebook@@@std@@$$QEAV?$vector@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@V?$allocator@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@@2@@4@PEAUINativeUIManager@12@@Z ?createUIManagerModule@react@facebook@@YA?AV?$unique_ptr@VCxxModule@module@xplat@facebook@@U?$default_delete@VCxxModule@module@xplat@facebook@@@std@@@std@@V?$shared_ptr@VIUIManager@react@facebook@@@4@@Z ?destroy@dynamic@folly@@AEAAXXZ -?dispatchCommand@ShadowNode@react@facebook@@UEAAX_JAEBUdynamic@folly@@@Z +?dispatchCommand@ShadowNode@react@facebook@@UEAAXAEBV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@AEBUdynamic@folly@@@Z ?getModuleRegistry@Instance@react@facebook@@QEAAAEAVModuleRegistry@23@XZ ?get_ptr@dynamic@folly@@QEGBAPEBU12@V?$Range@PEBD@2@@Z ?get_ptrImpl@dynamic@folly@@AEGBAPEBU12@AEBU12@@Z diff --git a/vnext/Desktop.DLL/react-native-win32.x86.def b/vnext/Desktop.DLL/react-native-win32.x86.def index 9ae703e4de2..8a299514bc9 100644 --- a/vnext/Desktop.DLL/react-native-win32.x86.def +++ b/vnext/Desktop.DLL/react-native-win32.x86.def @@ -35,7 +35,7 @@ EXPORTS ?createIUIManager@react@facebook@@YG?AV?$shared_ptr@VIUIManager@react@facebook@@@std@@$$QAV?$vector@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@V?$allocator@V?$unique_ptr@VIViewManager@react@facebook@@U?$default_delete@VIViewManager@react@facebook@@@std@@@std@@@2@@4@PAUINativeUIManager@12@@Z ?createUIManagerModule@react@facebook@@YG?AV?$unique_ptr@VCxxModule@module@xplat@facebook@@U?$default_delete@VCxxModule@module@xplat@facebook@@@std@@@std@@V?$shared_ptr@VIUIManager@react@facebook@@@4@@Z ?destroy@dynamic@folly@@AAEXXZ -?dispatchCommand@ShadowNode@react@facebook@@UAEX_JABUdynamic@folly@@@Z +?dispatchCommand@ShadowNode@react@facebook@@UAEXABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABUdynamic@folly@@@Z ?getModuleRegistry@Instance@react@facebook@@QAEAAVModuleRegistry@23@XZ ?get_ptr@dynamic@folly@@QGBEPBU12@V?$Range@PBD@2@@Z ?get_ptrImpl@dynamic@folly@@AGBEPBU12@ABU12@@Z diff --git a/vnext/Desktop.UnitTests/EmptyUIManagerModule.h b/vnext/Desktop.UnitTests/EmptyUIManagerModule.h index 6006bb2ca44..f8e333ea0bb 100644 --- a/vnext/Desktop.UnitTests/EmptyUIManagerModule.h +++ b/vnext/Desktop.UnitTests/EmptyUIManagerModule.h @@ -63,7 +63,10 @@ class EmptyUIManager { std::function /*final Callback*/ callback); void setJSResponder(int64_t reactTag, bool blockNativeResponder); void clearJSResponder(); - void dispatchViewManagerCommand(int64_t reactTag, int64_t commandId, folly::dynamic /*ReadableMap*/ commandArgs); + void dispatchViewManagerCommand( + int64_t reactTag, + const std::string &commandId, + folly::dynamic /*ReadableMap*/ commandArgs); void showPopupMenu( int64_t reactTag, folly::dynamic /*ReadableMap*/ items, diff --git a/vnext/Microsoft.ReactNative.SharedManaged/AttributedViewManager.cs b/vnext/Microsoft.ReactNative.SharedManaged/AttributedViewManager.cs index b590c2bfb96..56691b2be2f 100644 --- a/vnext/Microsoft.ReactNative.SharedManaged/AttributedViewManager.cs +++ b/vnext/Microsoft.ReactNative.SharedManaged/AttributedViewManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Linq.Expressions; using System.Reflection; using Windows.UI.Xaml; @@ -192,27 +193,21 @@ private static bool IsEnum(Type t) #region Commands - public virtual IReadOnlyDictionary Commands + public virtual IReadOnlyList Commands { get { if (null == _commands) { - var commands = new Dictionary(); + _commands = ViewManagerCommands.Keys.ToList(); - foreach (var kvp in ViewManagerCommands) - { - commands.Add(kvp.Value.CommandName, kvp.Value.CommandId); - } - - _commands = commands; } return _commands; } } - private IReadOnlyDictionary _commands; + private IReadOnlyList _commands; - public virtual void DispatchCommand(FrameworkElement view, long commandId, IJSValueReader commandArgsReader) + public virtual void DispatchCommand(FrameworkElement view, string commandId, IJSValueReader commandArgsReader) { if (view is TFrameworkElement viewAsT) { @@ -227,13 +222,13 @@ public virtual void DispatchCommand(FrameworkElement view, long commandId, IJSVa } } - internal Dictionary> ViewManagerCommands + internal Dictionary> ViewManagerCommands { get { if (null == _viewManagerCommands) { - var viewManagerCommands = new Dictionary>(); + var viewManagerCommands = new Dictionary>(); foreach (var methodInfo in GetType().GetTypeInfo().DeclaredMethods) { @@ -243,10 +238,9 @@ internal Dictionary> ViewManagerComm var command = new ViewManagerCommand { CommandName = commandAttribute.CommandName ?? methodInfo.Name, - CommandId = viewManagerCommands.Count, CommandMethod = MakeReaderMethod(methodInfo) }; - viewManagerCommands.Add(command.CommandId, command); + viewManagerCommands.Add(command.CommandName, command); } } @@ -255,12 +249,11 @@ internal Dictionary> ViewManagerComm return _viewManagerCommands; } } - private Dictionary> _viewManagerCommands; + private Dictionary> _viewManagerCommands; internal struct ViewManagerCommand where U : TFrameworkElement { public string CommandName; - public long CommandId; public Action CommandMethod; } diff --git a/vnext/Microsoft.ReactNative/ABIViewManager.cpp b/vnext/Microsoft.ReactNative/ABIViewManager.cpp index 0fd72679c1c..fc85aff39d0 100644 --- a/vnext/Microsoft.ReactNative/ABIViewManager.cpp +++ b/vnext/Microsoft.ReactNative/ABIViewManager.cpp @@ -115,29 +115,31 @@ void ABIViewManager::UpdateProperties(react::uwp::ShadowNodeBase *nodeToUpdate, } folly::dynamic ABIViewManager::GetCommands() const { - folly::dynamic innerParent = Super::GetCommands(); + folly::dynamic commandMap = folly::dynamic::object(); + // Why are we providing commands with the same key and value? React Native 0.61 internally introduced string command + // IDs which can be dispatched directly without querying the ViewManager for commands. Integer command IDs are + // internally deprecated, but querying for command ID is still the documented path. Returning constants as their + // string lets us internally only support the string path. if (m_viewManagerWithCommands) { - auto outerChild = m_viewManagerWithCommands.Commands(); - for (const auto &pair : outerChild) { - std::string key = to_string(pair.Key()); - folly::dynamic value{pair.Value()}; - innerParent.insert(key, value); + for (const auto &commandName : m_viewManagerWithCommands.Commands()) { + auto commandAsStr = to_string(commandName); + commandMap[commandAsStr] = commandAsStr; } } - return innerParent; + return commandMap; } void ABIViewManager::DispatchCommand( winrt::Windows::UI::Xaml::DependencyObject viewToUpdate, - int64_t commandId, + const std::string &commandId, const folly::dynamic &commandArgs) { if (m_viewManagerWithCommands) { auto view = viewToUpdate.as(); IJSValueReader argReader = winrt::make(commandArgs); - m_viewManagerWithCommands.DispatchCommand(view, commandId, argReader); + m_viewManagerWithCommands.DispatchCommand(view, to_hstring(commandId), argReader); } } diff --git a/vnext/Microsoft.ReactNative/ABIViewManager.h b/vnext/Microsoft.ReactNative/ABIViewManager.h index 4356f6dabeb..3b2e55ae57a 100644 --- a/vnext/Microsoft.ReactNative/ABIViewManager.h +++ b/vnext/Microsoft.ReactNative/ABIViewManager.h @@ -40,7 +40,7 @@ class ABIViewManager : public react::uwp::FrameworkElementViewManager { void DispatchCommand( winrt::Windows::UI::Xaml::DependencyObject viewToUpdate, - int64_t commandId, + const std::string &commandId, const folly::dynamic &commandArgs) override; folly::dynamic GetExportedCustomBubblingEventTypeConstants() const override; diff --git a/vnext/Microsoft.ReactNative/IViewManager.idl b/vnext/Microsoft.ReactNative/IViewManager.idl index 68598f48659..226bcf9703d 100644 --- a/vnext/Microsoft.ReactNative/IViewManager.idl +++ b/vnext/Microsoft.ReactNative/IViewManager.idl @@ -40,7 +40,7 @@ namespace Microsoft.ReactNative [webhosthidden] interface IViewManagerWithNativeProperties { - Windows.Foundation.Collections.IMapView NativeProps { get; }; + IMapView NativeProps { get; }; void UpdateProperties(Windows.UI.Xaml.FrameworkElement view, IJSValueReader propertyMapReader); } @@ -48,9 +48,9 @@ namespace Microsoft.ReactNative [webhosthidden] interface IViewManagerWithCommands { - Windows.Foundation.Collections.IMapView Commands { get; }; + IVectorView Commands { get; }; - void DispatchCommand(Windows.UI.Xaml.FrameworkElement view, Int64 commandId, IJSValueReader commandArgsReader); + void DispatchCommand(Windows.UI.Xaml.FrameworkElement view, String commandId, IJSValueReader commandArgsReader); } [webhosthidden] diff --git a/vnext/ReactUWP/Views/ScrollViewManager.cpp b/vnext/ReactUWP/Views/ScrollViewManager.cpp index 8e3a021ab84..bbe699e9e4b 100644 --- a/vnext/ReactUWP/Views/ScrollViewManager.cpp +++ b/vnext/ReactUWP/Views/ScrollViewManager.cpp @@ -11,10 +11,10 @@ namespace react { namespace uwp { -enum class ScrollViewCommands { - ScrollTo = 1, - ScrollToEnd, -}; +namespace ScrollViewCommands { +constexpr const char *ScrollTo = "scrollTo"; +constexpr const char *ScrollToEnd = "scrollToEnd"; +}; // namespace ScrollViewCommands class ScrollViewShadowNode : public ShadowNodeBase { using Super = ShadowNodeBase; @@ -22,7 +22,7 @@ class ScrollViewShadowNode : public ShadowNodeBase { public: ScrollViewShadowNode(); ~ScrollViewShadowNode(); - void dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) override; + void dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) override; void createView() override; void updateProperties(const folly::dynamic &&props) override; @@ -65,28 +65,23 @@ ScrollViewShadowNode::~ScrollViewShadowNode() { m_SIPEventHandler.reset(); } -void ScrollViewShadowNode::dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) { +void ScrollViewShadowNode::dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) { const auto scrollViewer = GetView().as(); if (scrollViewer == nullptr) return; - switch (commandId) { - case static_cast(ScrollViewCommands::ScrollTo): { - double x = commandArgs[0].asDouble(); - double y = commandArgs[1].asDouble(); - bool animated = commandArgs[2].asBool(); - scrollViewer.ChangeView(x, y, nullptr, !animated /*disableAnimation*/); - break; - } - case static_cast(ScrollViewCommands::ScrollToEnd): { - bool animated = commandArgs[0].asBool(); - bool horiz = scrollViewer.HorizontalScrollMode() == winrt::ScrollMode::Auto; - if (horiz) - scrollViewer.ChangeView(scrollViewer.ScrollableWidth(), nullptr, nullptr, !animated /*disableAnimation*/); - else - scrollViewer.ChangeView(nullptr, scrollViewer.ScrollableHeight(), nullptr, !animated /*disableAnimation*/); - break; - } + if (commandId == ScrollViewCommands::ScrollTo) { + double x = commandArgs[0].asDouble(); + double y = commandArgs[1].asDouble(); + bool animated = commandArgs[2].asBool(); + scrollViewer.ChangeView(x, y, nullptr, !animated /*disableAnimation*/); + } else if (commandId == ScrollViewCommands::ScrollToEnd) { + bool animated = commandArgs[0].asBool(); + bool horiz = scrollViewer.HorizontalScrollMode() == winrt::ScrollMode::Auto; + if (horiz) + scrollViewer.ChangeView(scrollViewer.ScrollableWidth(), nullptr, nullptr, !animated /*disableAnimation*/); + else + scrollViewer.ChangeView(nullptr, scrollViewer.ScrollableHeight(), nullptr, !animated /*disableAnimation*/); } } @@ -413,11 +408,10 @@ const char *ScrollViewManager::GetName() const { } folly::dynamic ScrollViewManager::GetCommands() const { - auto commands = Super::GetCommands(); - commands.update(folly::dynamic::object( - "scrollTo", static_cast>(ScrollViewCommands::ScrollTo))( - "scrollToEnd", static_cast>(ScrollViewCommands::ScrollToEnd))); - return commands; + // Upstream JS will dispatch the string directly instead of ever actually calling this, but providing a real + // implementation is simple enough in case anything changes. + return folly::dynamic::object(ScrollViewCommands::ScrollTo, ScrollViewCommands::ScrollTo)( + ScrollViewCommands::ScrollToEnd, ScrollViewCommands::ScrollToEnd); } folly::dynamic ScrollViewManager::GetNativeProps() const { diff --git a/vnext/ReactUWP/Views/ShadowNodeBase.cpp b/vnext/ReactUWP/Views/ShadowNodeBase.cpp index c03d97ed666..527c30e5a88 100644 --- a/vnext/ReactUWP/Views/ShadowNodeBase.cpp +++ b/vnext/ReactUWP/Views/ShadowNodeBase.cpp @@ -44,7 +44,7 @@ bool ShadowNodeBase::NeedsForceLayout() { return false; } -void ShadowNodeBase::dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) { +void ShadowNodeBase::dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) { GetViewManager()->DispatchCommand(GetView(), commandId, commandArgs); } diff --git a/vnext/ReactUWP/Views/SwitchViewManager.cpp b/vnext/ReactUWP/Views/SwitchViewManager.cpp index e5ad8a0c5a5..93093cdf36e 100644 --- a/vnext/ReactUWP/Views/SwitchViewManager.cpp +++ b/vnext/ReactUWP/Views/SwitchViewManager.cpp @@ -160,5 +160,17 @@ bool SwitchViewManager::UpdateProperty( return true; } +void SwitchViewManager::DispatchCommand( + XamlView viewToUpdate, + const std::string &commandId, + const folly::dynamic &commandArgs) { + if (commandId == "setValue") { + auto value = commandArgs[0].asBool(); + viewToUpdate.as().IsEnabled(value); + } else { + Super::DispatchCommand(viewToUpdate, commandId, commandArgs); + } +} + } // namespace uwp } // namespace react diff --git a/vnext/ReactUWP/Views/SwitchViewManager.h b/vnext/ReactUWP/Views/SwitchViewManager.h index aaa6089c809..372163eb095 100644 --- a/vnext/ReactUWP/Views/SwitchViewManager.h +++ b/vnext/ReactUWP/Views/SwitchViewManager.h @@ -17,6 +17,7 @@ class SwitchViewManager : public ControlViewManager { const char *GetName() const override; folly::dynamic GetNativeProps() const override; facebook::react::ShadowNode *createShadow() const override; + void DispatchCommand(XamlView viewToUpdate, const std::string &commandId, const folly::dynamic &commandArgs) override; protected: bool UpdateProperty( diff --git a/vnext/ReactUWP/Views/ViewManagerBase.cpp b/vnext/ReactUWP/Views/ViewManagerBase.cpp index 38feb176955..86d1e61e084 100644 --- a/vnext/ReactUWP/Views/ViewManagerBase.cpp +++ b/vnext/ReactUWP/Views/ViewManagerBase.cpp @@ -255,7 +255,7 @@ void ViewManagerBase::TransferProperties(XamlView /*oldView*/, XamlView /*newVie void ViewManagerBase::DispatchCommand( XamlView /*viewToUpdate*/, - int64_t /*commandId*/, + const std::string & /*commandId*/, const folly::dynamic & /*commandArgs*/) { assert(false); // View did not handle its command } diff --git a/vnext/ReactWindowsCore/IUIManager.h b/vnext/ReactWindowsCore/IUIManager.h index 4cf28835a16..cb677aa75aa 100644 --- a/vnext/ReactWindowsCore/IUIManager.h +++ b/vnext/ReactWindowsCore/IUIManager.h @@ -44,7 +44,8 @@ class IUIManager { folly::dynamic &addChildTags, folly::dynamic &addAtIndices, folly::dynamic &removeFrom) = 0; - virtual void dispatchViewManagerCommand(int64_t reactTag, int64_t commandId, folly::dynamic &&commandArgs) = 0; + virtual void + dispatchViewManagerCommand(int64_t reactTag, const std::string &commandId, folly::dynamic &&commandArgs) = 0; virtual void replaceExistingNonRootView(int64_t oldTag, int64_t newTag) = 0; virtual void measure(int64_t reactTag, facebook::xplat::module::CxxModule::Callback callback) = 0; virtual void measureInWindow(int64_t reactTag, facebook::xplat::module::CxxModule::Callback callback) = 0; diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp b/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp index b71f31bd556..7d72ac8d25a 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.cpp @@ -320,7 +320,10 @@ void UIManager::replaceExistingNonRootView(int64_t oldTag, int64_t newTag) { manageChildren(parent.m_tag, emptyVec, emptyVec, tagToAdd, indicesToAdd, indicesToRemove); } -void UIManager::dispatchViewManagerCommand(int64_t reactTag, int64_t commandId, folly::dynamic &&commandArgs) { +void UIManager::dispatchViewManagerCommand( + int64_t reactTag, + const std::string &commandId, + folly::dynamic &&commandArgs) { m_nativeUIManager->ensureInBatch(); auto &node = m_nodeRegistry.getNode(reactTag); if (!node.m_zombie) @@ -507,8 +510,11 @@ std::vector UIManagerModule::getMeth Method( "dispatchViewManagerCommand", [manager](dynamic args) { + // 0.61 allows directly dispatching command names instead of querying the ViewManager for the command ID. + // In stock React Native, integer commands are deprecated but not yet removed. RNW APIs only allow strings, + // and provide command constants as their literal string. manager->dispatchViewManagerCommand( - jsArgAsInt(args, 0), jsArgAsInt(args, 1), std::move(jsArgAsDynamic(args, 2))); + jsArgAsInt(args, 0), jsArgAsString(args, 1), std::move(jsArgAsDynamic(args, 2))); }), Method("measure", [manager](dynamic args, Callback cb) { manager->measure(jsArgAsInt(args, 0), cb); }), Method( diff --git a/vnext/ReactWindowsCore/Modules/UIManagerModule.h b/vnext/ReactWindowsCore/Modules/UIManagerModule.h index cf79bb89346..e66f5d5e9ac 100644 --- a/vnext/ReactWindowsCore/Modules/UIManagerModule.h +++ b/vnext/ReactWindowsCore/Modules/UIManagerModule.h @@ -43,7 +43,9 @@ class UIManager : public IUIManager, INativeUIManagerHost { folly::dynamic &addChildTags, folly::dynamic &addAtIndices, folly::dynamic &removeFrom) override; - void dispatchViewManagerCommand(int64_t reactTag, int64_t commandId, folly::dynamic &&commandArgs) override; + + void dispatchViewManagerCommand(int64_t reactTag, const std::string &commandId, folly::dynamic &&commandArgs) + override; void replaceExistingNonRootView(int64_t oldTag, int64_t newTag) override; void onBatchComplete() override; void measure(int64_t reactTag, facebook::xplat::module::CxxModule::Callback callback) override; diff --git a/vnext/ReactWindowsCore/ShadowNode.cpp b/vnext/ReactWindowsCore/ShadowNode.cpp index 6bf17eb9261..626015b0423 100644 --- a/vnext/ReactWindowsCore/ShadowNode.cpp +++ b/vnext/ReactWindowsCore/ShadowNode.cpp @@ -8,7 +8,7 @@ namespace react { ShadowNode::~ShadowNode() {} -void ShadowNode::dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) {} +void ShadowNode::dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) {} void ShadowNode::onDropViewInstance() {} diff --git a/vnext/ReactWindowsCore/ShadowNode.h b/vnext/ReactWindowsCore/ShadowNode.h index 4f986e2f108..ea10f0259db 100644 --- a/vnext/ReactWindowsCore/ShadowNode.h +++ b/vnext/ReactWindowsCore/ShadowNode.h @@ -20,7 +20,7 @@ struct ShadowNode { virtual void updateProperties(const folly::dynamic &&props); virtual void onDropViewInstance() = 0; - virtual void dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs); + virtual void dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs); virtual void removeAllChildren() = 0; virtual void AddView(ShadowNode &child, int64_t index) = 0; virtual void RemoveChildAt(int64_t indexToRemove) = 0; diff --git a/vnext/include/ReactUWP/Views/ShadowNodeBase.h b/vnext/include/ReactUWP/Views/ShadowNodeBase.h index e8ec8da550f..2e008780943 100644 --- a/vnext/include/ReactUWP/Views/ShadowNodeBase.h +++ b/vnext/include/ReactUWP/Views/ShadowNodeBase.h @@ -54,7 +54,7 @@ struct REACTWINDOWS_EXPORT ShadowNodeBase : public facebook::react::ShadowNode { virtual ~ShadowNodeBase() {} virtual void onDropViewInstance() override; - virtual void dispatchCommand(int64_t commandId, const folly::dynamic &commandArgs) override; + virtual void dispatchCommand(const std::string &commandId, const folly::dynamic &commandArgs) override; virtual void removeAllChildren() override; virtual void AddView(ShadowNode &child, int64_t index) override; virtual void RemoveChildAt(int64_t indexToRemove) override; diff --git a/vnext/include/ReactUWP/Views/ViewManagerBase.h b/vnext/include/ReactUWP/Views/ViewManagerBase.h index 17f2e2ae6c0..b1ff720d35a 100644 --- a/vnext/include/ReactUWP/Views/ViewManagerBase.h +++ b/vnext/include/ReactUWP/Views/ViewManagerBase.h @@ -62,7 +62,7 @@ class REACTWINDOWS_EXPORT ViewManagerBase : public facebook::react::IViewManager virtual void UpdateProperties(ShadowNodeBase *nodeToUpdate, const folly::dynamic &reactDiffMap); - virtual void DispatchCommand(XamlView viewToUpdate, int64_t commandId, const folly::dynamic &commandArgs); + virtual void DispatchCommand(XamlView viewToUpdate, const std::string &commandId, const folly::dynamic &commandArgs); // Yoga Layout virtual void From b105db4744b3d706cca883f68ded4b725e98fc9f Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 22 Apr 2020 15:02:43 -0700 Subject: [PATCH 2/2] Change files --- ...windows-2020-04-22-15-02-43-stringviewmanagertemp.json | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 change/react-native-windows-2020-04-22-15-02-43-stringviewmanagertemp.json diff --git a/change/react-native-windows-2020-04-22-15-02-43-stringviewmanagertemp.json b/change/react-native-windows-2020-04-22-15-02-43-stringviewmanagertemp.json new file mode 100644 index 00000000000..9470e6bc27a --- /dev/null +++ b/change/react-native-windows-2020-04-22-15-02-43-stringviewmanagertemp.json @@ -0,0 +1,8 @@ +{ + "type": "prerelease", + "comment": "Implement String ViewManager Command IDs", + "packageName": "react-native-windows", + "email": "ngerlem@microsoft.com", + "dependentChangeType": "patch", + "date": "2020-04-22T22:02:43.043Z" +}