-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Implement String ViewManager Command IDs #4667
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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" | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -105,18 +105,18 @@ void CustomUserControlViewManagerCpp::UpdateProperties( | |
| } | ||
|
|
||
| // IViewManagerWithCommands | ||
| IMapView<hstring, int64_t> CustomUserControlViewManagerCpp::Commands() noexcept { | ||
| auto commands = winrt::single_threaded_map<hstring, int64_t>(); | ||
| commands.Insert(L"CustomCommand", 0); | ||
| IVectorView<hstring> CustomUserControlViewManagerCpp::Commands() noexcept { | ||
| auto commands = winrt::single_threaded_vector<hstring>(); | ||
| commands.Append(L"CustomCommand"); | ||
| return commands.GetView(); | ||
| } | ||
|
|
||
| void CustomUserControlViewManagerCpp::DispatchCommand( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. since we are going to support both the int and string variants for the time being, should this be an overload rather than changing it to string so we can test both cases?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I touched on that a little in the PR description. Internal CPP code needs to support both, but the C++ view manager exposing IDs to implementers is a departure from the C# and ObjC view managers at least. This has some motivation to move the direction of only strings, but the bigger concern I had was around API confusion. I.e. you look at an interface and see a command id version and a string version. It's super opaque to know which to implement when. |
||
| FrameworkElement const &view, | ||
| int64_t commandId, | ||
| winrt::hstring const &commandId, | ||
| IJSValueReader const &commandArgsReader) noexcept { | ||
| if (auto control = view.try_as<winrt::SampleLibraryCpp::CustomUserControlCpp>()) { | ||
| if (commandId == 0) { | ||
| if (commandId == L"CustomCommand") { | ||
| std::string arg = std::to_string(winrt::unbox_value<int64_t>(view.Tag())); | ||
| arg.append(", \""); | ||
| arg.append(winrt::to_string(commandArgsReader.GetString())); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -115,29 +115,31 @@ void ABIViewManager::UpdateProperties(react::uwp::ShadowNodeBase *nodeToUpdate, | |
| } | ||
|
|
||
| folly::dynamic ABIViewManager::GetCommands() const { | ||
| folly::dynamic innerParent = Super::GetCommands(); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Our superclass always returned nothing, so removing it doesn't do anything in practice, but I don't think this should have been here to begin with. I.e. we don't dispatch to the superclass, so even if it did has commands to report, we could never actually run them.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. shouldn't we fix the "dispatching to the superclass isn't working" problem then? Can you file an issue if you can't fix it in this PR?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it's fine to expect the Base View Manager won't handle anything in this case. Right now the only thing it does is |
||
| 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; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. On the Flow side, View Manager commands are untyped. Was unable to confirm whether other platforms have moved to fully using strings over the bridge yet though. |
||
| } | ||
| } | ||
|
|
||
| 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<winrt::FrameworkElement>(); | ||
|
|
||
| IJSValueReader argReader = winrt::make<DynamicReader>(commandArgs); | ||
| m_viewManagerWithCommands.DispatchCommand(view, commandId, argReader); | ||
| m_viewManagerWithCommands.DispatchCommand(view, to_hstring(commandId), argReader); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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<winrt::ToggleSwitch>().IsEnabled(value); | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This command is kind of weird. It's iOS only upstream, and in their impl doesn't touch native props either. From what I can tell it's to fix an iOS quirk, but implementing it doesn't seem to cause us any issues, and let's us fully share iOS JS code. |
||
| } else { | ||
| Super::DispatchCommand(viewToUpdate, commandId, commandArgs); | ||
| } | ||
| } | ||
|
|
||
| } // namespace uwp | ||
| } // namespace react | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -255,7 +255,7 @@ void ViewManagerBase::TransferProperties(XamlView /*oldView*/, XamlView /*newVie | |
|
|
||
| void ViewManagerBase::DispatchCommand( | ||
| XamlView /*viewToUpdate*/, | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Since it is a new method, could you pass the parameter correctly by const& ? |
||
| int64_t /*commandId*/, | ||
| const std::string & /*commandId*/, | ||
| const folly::dynamic & /*commandArgs*/) { | ||
| assert(false); // View did not handle its command | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We shouldn't include React.cpp.props in projects external to the Microsoft.ReactNative boundary. We don't include it in the template project, and including it here actually led to it dropiing a ReactCommon folder on my C drive.