Skip to content

Commit 1d3fa40

Browse files
sammy-SCfacebook-github-bot
authored andcommitted
Add setNativeProps to Fabric
Summary: changelog: Introduce setNativeProps to Fabric Add support for `setNativeProps` in Fabric for backwards compatibility. It is still recommended to move away from `setNativeProps` because the API will not work with future features. We can make step [Migrating off setNativeProps](https://reactnative.dev/docs/new-architecture-library-intro#migrating-off-setnativeprops) in migration guide optional. Reviewed By: yungsters, mdvacca Differential Revision: D41521523 fbshipit-source-id: 4d9bbd6304b8c5ee24a36b33039ed33ae1fc21f8
1 parent 86786f1 commit 1d3fa40

18 files changed

+165
-15
lines changed

React/Fabric/Mounting/RCTMountingManager.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
#import <React/RCTMountingManagerDelegate.h>
1111
#import <React/RCTPrimitives.h>
1212
#import <react/renderer/core/ComponentDescriptor.h>
13+
#import <react/renderer/core/RawProps.h>
1314
#import <react/renderer/core/ReactPrimitives.h>
1415
#import <react/renderer/mounting/MountingCoordinator.h>
1516
#import <react/renderer/mounting/ShadowView.h>
@@ -55,6 +56,13 @@ NS_ASSUME_NONNULL_BEGIN
5556
*/
5657
- (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName args:(NSArray *)args;
5758

59+
/**
60+
* Set props on native view directly. It is a performance shortcut that skips render pipeline.
61+
* This is a backport of setNativeProps from the old architecture and will be removed in the future.
62+
* Can be called from any thread.
63+
*/
64+
- (void)setNativeProps_DEPRECATED:(ReactTag)reactTag withProps:(facebook::react::Props::Shared)props;
65+
5866
/**
5967
* Dispatch an accessibility event to be performed on the main thread.
6068
* Can be called from any thread.

React/Fabric/Mounting/RCTMountingManager.mm

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,24 @@ - (void)dispatchCommand:(ReactTag)reactTag commandName:(NSString *)commandName a
225225
}
226226

227227
RCTExecuteOnMainQueue(^{
228-
RCTAssertMainQueue();
229228
[self synchronouslyDispatchCommandOnUIThread:reactTag commandName:commandName args:args];
230229
});
231230
}
232231

232+
- (void)setNativeProps_DEPRECATED:(ReactTag)reactTag withProps:(Props::Shared)props
233+
{
234+
if (RCTIsMainQueue()) {
235+
UIView<RCTComponentViewProtocol> *componentView = [_componentViewRegistry findComponentViewWithTag:reactTag];
236+
Props::Shared oldProps = [componentView props];
237+
[componentView updateProps:props oldProps:oldProps];
238+
[componentView finalizeUpdates:RNComponentViewUpdateMaskProps];
239+
return;
240+
}
241+
RCTExecuteOnMainQueue(^{
242+
[self setNativeProps_DEPRECATED:reactTag withProps:std::move(props)];
243+
});
244+
}
245+
233246
- (void)sendAccessibilityEvent:(ReactTag)reactTag eventType:(NSString *)eventType
234247
{
235248
if (RCTIsMainQueue()) {
@@ -241,7 +254,6 @@ - (void)sendAccessibilityEvent:(ReactTag)reactTag eventType:(NSString *)eventTyp
241254
}
242255

243256
RCTExecuteOnMainQueue(^{
244-
RCTAssertMainQueue();
245257
[self synchronouslyDispatchAccessbilityEventOnUIThread:reactTag eventType:eventType];
246258
});
247259
}

React/Fabric/RCTScheduler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ NS_ASSUME_NONNULL_BEGIN
3434
commandName:(std::string const &)commandName
3535
args:(folly::dynamic const &)args;
3636

37+
- (void)setNativeProps_DEPRECATED:(facebook::react::ShadowView const &)shadowView
38+
withProps:(facebook::react::Props::Shared)props;
39+
3740
- (void)schedulerDidSendAccessibilityEvent:(facebook::react::ShadowView const &)shadowView
3841
eventType:(std::string const &)eventType;
3942

React/Fabric/RCTScheduler.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,12 @@ void schedulerDidDispatchCommand(
4545
[scheduler.delegate schedulerDidDispatchCommand:shadowView commandName:commandName args:args];
4646
}
4747

48+
void setNativeProps_DEPRECATED(const ShadowView &shadowView, Props::Shared props) override
49+
{
50+
RCTScheduler *scheduler = (__bridge RCTScheduler *)scheduler_;
51+
[scheduler.delegate setNativeProps_DEPRECATED:shadowView withProps:std::move(props)];
52+
}
53+
4854
void schedulerDidSetIsJSResponder(ShadowView const &shadowView, bool isJSResponder, bool blockNativeResponder)
4955
override
5056
{

React/Fabric/RCTSurfacePresenter.mm

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -372,6 +372,12 @@ - (void)schedulerDidDispatchCommand:(ShadowView const &)shadowView
372372
[_mountingManager dispatchCommand:tag commandName:commandStr args:argsArray];
373373
}
374374

375+
- (void)setNativeProps_DEPRECATED:(ShadowView const &)shadowView withProps:(Props::Shared)props
376+
{
377+
ReactTag tag = shadowView.tag;
378+
[self->_mountingManager setNativeProps_DEPRECATED:tag withProps:props];
379+
}
380+
375381
- (void)schedulerDidSendAccessibilityEvent:(const facebook::react::ShadowView &)shadowView
376382
eventType:(const std::string &)eventType
377383
{

ReactAndroid/src/main/jni/react/fabric/Binding.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,12 @@ void Binding::schedulerDidDispatchCommand(
549549
mountingManager->dispatchCommand(shadowView, commandName, args);
550550
}
551551

552+
void Binding::setNativeProps_DEPRECATED(
553+
const ShadowView &shadowView,
554+
Props::Shared props) {
555+
// TODO(T130729920): Add Android implementation for setNativeProps.
556+
}
557+
552558
void Binding::schedulerDidSendAccessibilityEvent(
553559
const ShadowView &shadowView,
554560
std::string const &eventType) {

ReactAndroid/src/main/jni/react/fabric/Binding.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,10 @@ class Binding : public jni::HybridClass<Binding>,
107107
std::string const &commandName,
108108
folly::dynamic const &args) override;
109109

110+
void setNativeProps_DEPRECATED(
111+
const ShadowView &shadowView,
112+
Props::Shared props) override;
113+
110114
void schedulerDidSendAccessibilityEvent(
111115
const ShadowView &shadowView,
112116
std::string const &eventType) override;

ReactCommon/react/renderer/components/view/YogaLayoutableShadowNode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -202,6 +202,7 @@ void YogaLayoutableShadowNode::adoptYogaChild(size_t index) {
202202
// react_native_assert(layoutableChildNode.yogaNode_.isDirty());
203203
} else {
204204
// The child is owned by some other node, we need to clone that.
205+
// TODO: At this point, React has wrong reference to the node. (T138668036)
205206
auto clonedChildNode = childNode.clone({});
206207
auto &layoutableClonedChildNode =
207208
traitCast<YogaLayoutableShadowNode const &>(*clonedChildNode);

ReactCommon/react/renderer/core/DynamicPropsUtilities.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "DynamicPropsUtilities.h"
99

1010
namespace facebook::react {
11+
1112
folly::dynamic mergeDynamicProps(
1213
folly::dynamic const &source,
1314
folly::dynamic const &patch) {
@@ -30,4 +31,8 @@ folly::dynamic mergeDynamicProps(
3031
return result;
3132
}
3233

34+
RawProps mergeRawProps(folly::dynamic const &source, RawProps const &patch) {
35+
return {mergeDynamicProps((folly::dynamic)source, (folly::dynamic)patch)};
36+
}
37+
3338
} // namespace facebook::react

ReactCommon/react/renderer/core/DynamicPropsUtilities.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
#pragma once
99

1010
#include <folly/dynamic.h>
11+
#include <react/renderer/core/RawProps.h>
1112

12-
namespace facebook {
13-
namespace react {
13+
namespace facebook::react {
1414

1515
folly::dynamic mergeDynamicProps(
1616
folly::dynamic const &source,
1717
folly::dynamic const &patch);
1818

19-
} // namespace react
20-
} // namespace facebook
19+
RawProps mergeRawProps(folly::dynamic const &source, RawProps const &patch);
20+
21+
} // namespace facebook::react

ReactCommon/react/renderer/core/ShadowNodeFamily.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,13 @@ class ShadowNodeFamily final {
8686
void dispatchRawState(StateUpdate &&stateUpdate, EventPriority priority)
8787
const;
8888

89+
/*
90+
* Holds currently applied native props. `nullptr` if setNativeProps API is
91+
* not used. It is used to backport setNativeProps API from the old
92+
* architecture and will be removed in the future.
93+
*/
94+
mutable std::unique_ptr<folly::dynamic> nativeProps_DEPRECATED;
95+
8996
private:
9097
friend ShadowNode;
9198
friend ShadowNodeFamilyFragment;

ReactCommon/react/renderer/scheduler/Scheduler.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,17 @@ void Scheduler::uiManagerDidDispatchCommand(
321321
}
322322
}
323323

324+
void Scheduler::setNativeProps_DEPRECATED(
325+
const ShadowNode::Shared &shadowNode,
326+
Props::Shared props) {
327+
SystraceSection s("Scheduler::setNativeProps_DEPRECATED");
328+
329+
if (delegate_ != nullptr) {
330+
auto shadowView = ShadowView(*shadowNode);
331+
delegate_->setNativeProps_DEPRECATED(shadowView, std::move(props));
332+
}
333+
}
334+
324335
void Scheduler::uiManagerDidSendAccessibilityEvent(
325336
const ShadowNode::Shared &shadowNode,
326337
std::string const &eventType) {

ReactCommon/react/renderer/scheduler/Scheduler.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ class Scheduler final : public UIManagerDelegate {
9494
const ShadowNode::Shared &shadowNode,
9595
std::string const &commandName,
9696
folly::dynamic const &args) override;
97+
void setNativeProps_DEPRECATED(
98+
const ShadowNode::Shared &shadowNode,
99+
Props::Shared props) override;
97100
void uiManagerDidSendAccessibilityEvent(
98101
const ShadowNode::Shared &shadowNode,
99102
std::string const &eventType) override;

ReactCommon/react/renderer/scheduler/SchedulerDelegate.h

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,7 @@
1313
#include <react/renderer/mounting/MountingCoordinator.h>
1414
#include <react/renderer/mounting/ShadowView.h>
1515

16-
namespace facebook {
17-
namespace react {
16+
namespace facebook::react {
1817

1918
/*
2019
* Abstract class for Scheduler's delegate.
@@ -41,6 +40,10 @@ class SchedulerDelegate {
4140
std::string const &commandName,
4241
folly::dynamic const &args) = 0;
4342

43+
virtual void setNativeProps_DEPRECATED(
44+
const ShadowView &shadowView,
45+
Props::Shared props) = 0;
46+
4447
virtual void schedulerDidSendAccessibilityEvent(
4548
const ShadowView &shadowView,
4649
std::string const &eventType) = 0;
@@ -56,5 +59,4 @@ class SchedulerDelegate {
5659
virtual ~SchedulerDelegate() noexcept = default;
5760
};
5861

59-
} // namespace react
60-
} // namespace facebook
62+
} // namespace facebook::react

ReactCommon/react/renderer/uimanager/UIManager.cpp

Lines changed: 49 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include "UIManager.h"
99

1010
#include <react/debug/react_native_assert.h>
11+
#include <react/renderer/core/DynamicPropsUtilities.h>
1112
#include <react/renderer/core/PropsParserContext.h>
1213
#include <react/renderer/core/ShadowNodeFragment.h>
1314
#include <react/renderer/debug/SystraceSection.h>
@@ -109,14 +110,29 @@ ShadowNode::Shared UIManager::cloneNode(
109110
shadowNode.getFamily().getSurfaceId(), *contextContainer_.get()};
110111

111112
auto &componentDescriptor = shadowNode.getComponentDescriptor();
113+
auto &family = shadowNode.getFamily();
114+
auto props = ShadowNodeFragment::propsPlaceholder();
115+
116+
if (rawProps != nullptr) {
117+
if (family.nativeProps_DEPRECATED != nullptr) {
118+
family.nativeProps_DEPRECATED =
119+
std::make_unique<folly::dynamic>(mergeDynamicProps(
120+
(folly::dynamic)*rawProps, *family.nativeProps_DEPRECATED));
121+
122+
props = componentDescriptor.cloneProps(
123+
propsParserContext,
124+
shadowNode.getProps(),
125+
mergeRawProps(*family.nativeProps_DEPRECATED, *rawProps));
126+
} else {
127+
props = componentDescriptor.cloneProps(
128+
propsParserContext, shadowNode.getProps(), *rawProps);
129+
}
130+
}
131+
112132
auto clonedShadowNode = componentDescriptor.cloneShadowNode(
113133
shadowNode,
114134
{
115-
/* .props = */
116-
rawProps != nullptr
117-
? componentDescriptor.cloneProps(
118-
propsParserContext, shadowNode.getProps(), *rawProps)
119-
: ShadowNodeFragment::propsPlaceholder(),
135+
/* .props = */ props,
120136
/* .children = */ children,
121137
});
122138

@@ -329,6 +345,34 @@ void UIManager::dispatchCommand(
329345
}
330346
}
331347

348+
void UIManager::setNativeProps_DEPRECATED(
349+
ShadowNode::Shared const &shadowNode,
350+
RawProps const &rawProps) const {
351+
if (delegate_ != nullptr) {
352+
auto &family = shadowNode->getFamily();
353+
if (family.nativeProps_DEPRECATED) {
354+
family.nativeProps_DEPRECATED =
355+
std::make_unique<folly::dynamic>(mergeDynamicProps(
356+
*family.nativeProps_DEPRECATED, (folly::dynamic)rawProps));
357+
} else {
358+
family.nativeProps_DEPRECATED =
359+
std::make_unique<folly::dynamic>((folly::dynamic)rawProps);
360+
}
361+
362+
PropsParserContext propsParserContext{
363+
family.getSurfaceId(), *contextContainer_.get()};
364+
auto &componentDescriptor =
365+
componentDescriptorRegistry_->at(shadowNode->getComponentHandle());
366+
367+
auto props = componentDescriptor.cloneProps(
368+
propsParserContext,
369+
getNewestCloneOfShadowNode(*shadowNode)->getProps(),
370+
RawProps(*family.nativeProps_DEPRECATED));
371+
372+
delegate_->setNativeProps_DEPRECATED(shadowNode, std::move(props));
373+
}
374+
}
375+
332376
void UIManager::sendAccessibilityEvent(
333377
const ShadowNode::Shared &shadowNode,
334378
std::string const &eventType) {

ReactCommon/react/renderer/uimanager/UIManager.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,10 @@ class UIManager final : public ShadowTreeDelegate {
162162
std::string const &commandName,
163163
folly::dynamic const &args) const;
164164

165+
void setNativeProps_DEPRECATED(
166+
ShadowNode::Shared const &shadowNode,
167+
RawProps const &rawProps) const;
168+
165169
void sendAccessibilityEvent(
166170
const ShadowNode::Shared &shadowNode,
167171
std::string const &eventType);

ReactCommon/react/renderer/uimanager/UIManagerBinding.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,24 @@ jsi::Value UIManagerBinding::get(
501501
});
502502
}
503503

504+
if (methodName == "setNativeProps") {
505+
return jsi::Function::createFromHostFunction(
506+
runtime,
507+
name,
508+
2,
509+
[uiManager](
510+
jsi::Runtime &runtime,
511+
const jsi::Value &,
512+
const jsi::Value *arguments,
513+
size_t) -> jsi::Value {
514+
uiManager->setNativeProps_DEPRECATED(
515+
shadowNodeFromValue(runtime, arguments[0]),
516+
RawProps(runtime, arguments[1]));
517+
518+
return jsi::Value::undefined();
519+
});
520+
}
521+
504522
// Legacy API
505523
if (methodName == "measureLayout") {
506524
return jsi::Function::createFromHostFunction(

ReactCommon/react/renderer/uimanager/UIManagerDelegate.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ class UIManagerDelegate {
4040
std::string const &commandName,
4141
folly::dynamic const &args) = 0;
4242

43+
/*
44+
* Called when UIManager wants directly manipulate view on the mounting layer.
45+
* This is a backport of setNativeProps from the old architecture and will be
46+
* removed in the future.
47+
*/
48+
virtual void setNativeProps_DEPRECATED(
49+
const ShadowNode::Shared &shadowNode,
50+
Props::Shared props) = 0;
51+
4352
/*
4453
* Called when UIManager wants to dispatch some accessibility event
4554
* to the mounting layer. eventType is platform-specific and not all

0 commit comments

Comments
 (0)