Include instanceHandle in cloning mechanism

Reviewed By: shergin, achen1

Differential Revision: D8072075

fbshipit-source-id: 2fcfdfa5116850ce0bac6c2c86d87e5bf00fd7f0
This commit is contained in:
David Vacca 2018-05-30 21:49:15 -07:00 committed by Facebook Github Bot
parent 40c7248345
commit 23fbd312aa
13 changed files with 126 additions and 73 deletions

View File

@ -120,17 +120,20 @@ public class FabricReconciler {
int reactTag = node.getReactTag();
if (DEBUG) {
Log.d(
TAG,
"manageChildren.enqueueUpdateProperties " +
"\n\ttag: " + reactTag +
"\n\tviewClass: " + node.getViewClass() +
"\n\tnewProps: " + node.getNewProps());
TAG,
"manageChildren.enqueueUpdateProperties " +
"\n\ttag: " + reactTag +
"\n\tviewClass: " + node.getViewClass() +
"\n\tinstanceHandle: " + node.getInstanceHandle() +
"\n\tnewProps: " + node.getNewProps());
}
if (node.getNewProps() != null) {
uiViewOperationQueue.enqueueUpdateProperties(
reactTag, node.getViewClass(), node.getNewProps());
}
}
uiViewOperationQueue.enqueueUpdateInstanceHandle(
reactTag, node.getInstanceHandle());
}
}

View File

@ -98,6 +98,7 @@ public class FabricUIManager implements UIManager, JSHandler {
ReactShadowNode rootNode = getRootNode(rootTag);
node.setRootTag(rootNode.getReactTag());
node.setViewClassName(viewName);
node.setInstanceHandle(instanceHandle);
node.setReactTag(reactTag);
node.setThemedContext(rootNode.getThemedContext());
@ -139,8 +140,7 @@ public class FabricUIManager implements UIManager, JSHandler {
Log.d(TAG, "cloneNode \n\tnode: " + node);
}
try {
// TODO: Pass new instanceHandle
ReactShadowNode clone = node.mutableCopy();
ReactShadowNode clone = node.mutableCopy(instanceHandle);
assertReactShadowNodeCopy(node, clone);
return clone;
} catch (Throwable t) {
@ -160,8 +160,7 @@ public class FabricUIManager implements UIManager, JSHandler {
Log.d(TAG, "cloneNodeWithNewChildren \n\tnode: " + node);
}
try {
// TODO: Pass new instanceHandle
ReactShadowNode clone = node.mutableCopyWithNewChildren();
ReactShadowNode clone = node.mutableCopyWithNewChildren(instanceHandle);
assertReactShadowNodeCopy(node, clone);
return clone;
} catch (Throwable t) {
@ -182,9 +181,8 @@ public class FabricUIManager implements UIManager, JSHandler {
Log.d(TAG, "cloneNodeWithNewProps \n\tnode: " + node + "\n\tprops: " + newProps);
}
try {
// TODO: Pass new instanceHandle
ReactShadowNode clone =
node.mutableCopyWithNewProps(newProps == null ? null : new ReactStylesDiffMap(newProps));
ReactShadowNode clone = node.mutableCopyWithNewProps(instanceHandle,
newProps == null ? null : new ReactStylesDiffMap(newProps));
assertReactShadowNodeCopy(node, clone);
return clone;
} catch (Throwable t) {
@ -206,9 +204,8 @@ public class FabricUIManager implements UIManager, JSHandler {
Log.d(TAG, "cloneNodeWithNewChildrenAndProps \n\tnode: " + node + "\n\tnewProps: " + newProps);
}
try {
// TODO: Pass new instanceHandle
ReactShadowNode clone =
node.mutableCopyWithNewChildrenAndProps(
node.mutableCopyWithNewChildrenAndProps(instanceHandle,
newProps == null ? null : new ReactStylesDiffMap(newProps));
assertReactShadowNodeCopy(node, clone);
return clone;
@ -244,7 +241,7 @@ public class FabricUIManager implements UIManager, JSHandler {
// then we add a mutation of it. In the future this will be performed by FabricJS / Fiber.
//TODO: T27926878 avoid cloning shared child
if (child.getParent() != null) {
child = child.mutableCopy();
child = child.mutableCopy(child.getInstanceHandle());
}
parent.addChildAt(child, parent.getChildCount());
} catch (Throwable t) {
@ -315,7 +312,7 @@ public class FabricUIManager implements UIManager, JSHandler {
private ReactShadowNode calculateDiffingAndCreateNewRootNode(
ReactShadowNode currentRootShadowNode, List<ReactShadowNode> newChildList) {
ReactShadowNode newRootShadowNode = currentRootShadowNode.mutableCopyWithNewChildren();
ReactShadowNode newRootShadowNode = currentRootShadowNode.mutableCopyWithNewChildren(currentRootShadowNode.getInstanceHandle());
for (ReactShadowNode child : newChildList) {
appendChild(newRootShadowNode, child);
}
@ -489,10 +486,10 @@ public class FabricUIManager implements UIManager, JSHandler {
// -> call to C++
}
public long createEventTarget(int targetTag) throws IllegalStateException {
long instanceHandle = mNativeViewHierarchyManager.getInstanceHandle(targetTag);
public long createEventTarget(int reactTag) throws IllegalStateException {
long instanceHandle = mNativeViewHierarchyManager.getInstanceHandle(reactTag);
if (instanceHandle == 0) {
throw new IllegalStateException("View with targetTag " + targetTag + " does not exist.");
throw new IllegalStateException("View with reactTag " + reactTag + " does not exist.");
}
// TODO: uncomment after diff including Binding is landed

View File

@ -221,16 +221,16 @@ public class NativeViewHierarchyManager {
@Nullable
@TargetApi(Build.VERSION_CODES.DONUT)
public long getInstanceHandle(int targetTag) {
public long getInstanceHandle(int reactTag) {
UiThreadUtil.assertOnUiThread();
View view = mTagsToViews.get(targetTag);
View view = mTagsToViews.get(reactTag);
if (view == null) {
throw new IllegalArgumentException("Unable to find view for tag: " + targetTag);
throw new IllegalArgumentException("Unable to find view for tag: " + reactTag);
}
Long tag = (Long) view.getTag(R.id.view_tag_instance_handle);
if (tag == null) {
throw new IllegalArgumentException("Unable to find instanceHandle for tag: " + targetTag);
throw new IllegalArgumentException("Unable to find instanceHandle for tag: " + reactTag);
}
return tag;
}

View File

@ -71,13 +71,13 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
/**
* @return a mutable copy of the {@link ReactShadowNode}
*/
T mutableCopy();
T mutableCopy(long instanceHandle);
T mutableCopyWithNewProps(@Nullable ReactStylesDiffMap newProps);
T mutableCopyWithNewProps(long instanceHandle, @Nullable ReactStylesDiffMap newProps);
T mutableCopyWithNewChildren();
T mutableCopyWithNewChildren(long instanceHandle);
T mutableCopyWithNewChildrenAndProps(@Nullable ReactStylesDiffMap newProps);
T mutableCopyWithNewChildrenAndProps(long instanceHandle, @Nullable ReactStylesDiffMap newProps);
String getViewClass();
@ -373,4 +373,8 @@ public interface ReactShadowNode<T extends ReactShadowNode> {
@Nullable ReactShadowNode getOriginalReactShadowNode();
void setOriginalReactShadowNode(@Nullable ReactShadowNode node);
long getInstanceHandle();
void setInstanceHandle(long instanceHandle);
}

View File

@ -81,7 +81,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
+ parentReactShadowNode + " index: " + childIndex);
}
ReactShadowNodeImpl newNode = oldReactShadowNode.mutableCopy();
ReactShadowNodeImpl newNode = oldReactShadowNode.mutableCopy(oldReactShadowNode.getInstanceHandle());
parentReactShadowNode.replaceChild(newNode, childIndex);
return newNode.mYogaNode;
}
@ -114,6 +114,7 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
private ReactShadowNode mOriginalReactShadowNode = null;
private @Nullable ReactStylesDiffMap mNewProps;
private long mInstanceHandle;
public ReactShadowNodeImpl() {
mDefaultPadding = new Spacing(0);
@ -166,11 +167,12 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
@Override
public ReactShadowNodeImpl mutableCopy() {
public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
ReactShadowNodeImpl copy = copy();
Assertions.assertCondition(
getClass() == copy.getClass(),
"Copied shadow node must use the same class");
copy.mInstanceHandle = instanceHandle;
if (mYogaNode != null) {
copy.mYogaNode = mYogaNode.clone();
copy.mYogaNode.setData(copy);
@ -185,8 +187,9 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewChildren() {
public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
ReactShadowNodeImpl copy = copy();
copy.mInstanceHandle = instanceHandle;
Assertions.assertCondition(
getClass() == copy.getClass(),
"Copied shadow node must use the same class");
@ -204,8 +207,9 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewProps(@Nullable ReactStylesDiffMap newProps) {
ReactShadowNodeImpl copy = mutableCopy();
public ReactShadowNodeImpl mutableCopyWithNewProps(long instanceHandle,
@Nullable ReactStylesDiffMap newProps) {
ReactShadowNodeImpl copy = mutableCopy(instanceHandle);
if (newProps != null) {
copy.updateProperties(newProps);
copy.mNewProps = newProps;
@ -214,8 +218,9 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewChildrenAndProps(@Nullable ReactStylesDiffMap newProps) {
ReactShadowNodeImpl copy = mutableCopyWithNewChildren();
public ReactShadowNodeImpl mutableCopyWithNewChildrenAndProps(long instanceHandle,
@Nullable ReactStylesDiffMap newProps) {
ReactShadowNodeImpl copy = mutableCopyWithNewChildren(instanceHandle);
if (newProps != null) {
copy.updateProperties(newProps);
copy.mNewProps = newProps;
@ -1107,4 +1112,14 @@ public class ReactShadowNodeImpl implements ReactShadowNode<ReactShadowNodeImpl>
public void setOriginalReactShadowNode(ReactShadowNode node) {
mOriginalReactShadowNode = node;
}
@Override
public long getInstanceHandle() {
return mInstanceHandle;
}
@Override
public void setInstanceHandle(long instanceHandle) {
mInstanceHandle = instanceHandle;
}
}

View File

@ -53,8 +53,8 @@ public class ProgressBarShadowNode extends LayoutShadowNode implements YogaMeasu
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewChildren() {
ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopyWithNewChildren();
public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
node.initMeasureFunction();
return node;
}
@ -64,8 +64,8 @@ public class ProgressBarShadowNode extends LayoutShadowNode implements YogaMeasu
}
@Override
public ReactShadowNodeImpl mutableCopy() {
ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopy();
public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
ProgressBarShadowNode node = (ProgressBarShadowNode) super.mutableCopy(instanceHandle);
node.initMeasureFunction();
return node;
}

View File

@ -62,15 +62,15 @@ public class ReactSliderManager extends SimpleViewManager<ReactSlider> {
}
@Override
public ReactShadowNodeImpl mutableCopy() {
ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopy();
public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopy(instanceHandle);
reactShadowNode.initMeasureFunction();
return reactShadowNode;
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewChildren() {
ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopyWithNewChildren();
public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
ReactSliderShadowNode reactShadowNode = (ReactSliderShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
reactShadowNode.initMeasureFunction();
return reactShadowNode;
}

View File

@ -55,15 +55,15 @@ public class ReactSwitchManager extends SimpleViewManager<ReactSwitch> {
}
@Override
public ReactShadowNodeImpl mutableCopy() {
ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopy();
public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopy(instanceHandle);
reactShadowNode.initMeasureFunction();
return reactShadowNode;
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewChildren() {
ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopyWithNewChildren();
public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
ReactSwitchShadowNode reactShadowNode = (ReactSwitchShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
reactShadowNode.initMeasureFunction();
return reactShadowNode;
}

View File

@ -159,15 +159,15 @@ public class ReactTextShadowNode extends ReactBaseTextShadowNode {
}
@Override
public ReactShadowNodeImpl mutableCopy() {
ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopy();
public ReactShadowNodeImpl mutableCopy(long instanceHandle) {
ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopy(instanceHandle);
copy.initMeasureFunction();
return copy;
}
@Override
public ReactShadowNodeImpl mutableCopyWithNewChildren() {
ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopyWithNewChildren();
public ReactShadowNodeImpl mutableCopyWithNewChildren(long instanceHandle) {
ReactTextShadowNode copy = (ReactTextShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
copy.initMeasureFunction();
return copy;
}

View File

@ -65,8 +65,8 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
}
@Override
public ReactTextInputShadowNode mutableCopy() {
ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopy();
public ReactTextInputShadowNode mutableCopy(long instanceHandle) {
ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopy(instanceHandle);
node.initMeasureFunction();
ThemedReactContext themedContext = getThemedContext();
if (themedContext != null) {
@ -80,8 +80,8 @@ public class ReactTextInputShadowNode extends ReactBaseTextShadowNode
}
@Override
public ReactTextInputShadowNode mutableCopyWithNewChildren() {
ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopyWithNewChildren();
public ReactTextInputShadowNode mutableCopyWithNewChildren(long instanceHandle) {
ReactTextInputShadowNode node = (ReactTextInputShadowNode) super.mutableCopyWithNewChildren(instanceHandle);
node.initMeasureFunction();
ThemedReactContext themedContext = getThemedContext();
if (themedContext != null) {

View File

@ -0,0 +1,20 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
package com.facebook.react.bridge;
import java.util.Random;
public class InstanceHandleHelper {
private static final Random random = new Random();
public static long randomInstanceHandle() {
return random.nextLong();
}
}

View File

@ -2,6 +2,7 @@
package com.facebook.react.fabric;
import static org.fest.assertions.api.Assertions.assertThat;
import static com.facebook.react.bridge.InstanceHandleHelper.randomInstanceHandle;
import com.facebook.react.ReactRootView;
import com.facebook.react.bridge.ReactApplicationContext;
@ -28,6 +29,7 @@ import org.junit.runner.RunWith;
import org.robolectric.RobolectricTestRunner;
import org.robolectric.RuntimeEnvironment;
/** Tests {@link FabricUIManager} */
@RunWith(RobolectricTestRunner.class)
public class FabricUIManagerTest {
@ -35,7 +37,6 @@ public class FabricUIManagerTest {
private FabricUIManager mFabricUIManager;
private ThemedReactContext mThemedReactContext;
private int mNextReactTag;
private int mNextInstanceHandle;
@Before
public void setUp() throws Exception {
@ -58,10 +59,9 @@ public class FabricUIManagerTest {
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = mFabricUIManager.addRootView(rootView);
int reactTag = mNextReactTag++;
int instanceHandle = mNextInstanceHandle++;
String viewClass = ReactViewManager.REACT_CLASS;
ReactShadowNode node =
mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, instanceHandle);
mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, randomInstanceHandle());
assertThat(reactTag).isEqualTo(node.getReactTag());
assertThat(viewClass).isEqualTo(node.getViewClass());
@ -79,10 +79,9 @@ public class FabricUIManagerTest {
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = mFabricUIManager.addRootView(rootView);
int reactTag = mNextReactTag++;
int instanceHandle = mNextInstanceHandle++;
String viewClass = ReactViewManager.REACT_CLASS;
ReactShadowNode node =
mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, instanceHandle);
mFabricUIManager.createNode(reactTag, viewClass, rootTag, null, randomInstanceHandle());
List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(rootTag);
mFabricUIManager.appendChildToSet(childSet, node);
@ -106,6 +105,21 @@ public class FabricUIManagerTest {
assertThat(clonedNode.getChildAt(0)).isEqualTo(child);
}
@Test
public void testCloneWithInstanceHandle() {
ReactShadowNode node = createViewNode();
long oldInstanceHandle = node.getInstanceHandle();
long newInstanceHandle = oldInstanceHandle + 1;
ReactShadowNode clonedNode = mFabricUIManager.cloneNode(node, newInstanceHandle);
assertThat(clonedNode).isNotSameAs(node);
assertThat(clonedNode.getInstanceHandle()).isSameAs(newInstanceHandle);
assertThat(node.getInstanceHandle()).isSameAs(oldInstanceHandle);
}
@Test
public void testDefaultSpacingCloning() {
ReactShadowNode node = createViewNode();
@ -124,7 +138,7 @@ public class FabricUIManagerTest {
node.setText("test");
assertThat(node.isVirtual()).isTrue();
ReactRawTextShadowNode clonedNode = (ReactRawTextShadowNode) node.mutableCopy();
ReactRawTextShadowNode clonedNode = (ReactRawTextShadowNode) node.mutableCopy(randomInstanceHandle());
assertThat(clonedNode.getText()).isEqualTo("test");
assertThat(clonedNode).isNotEqualTo(node);
@ -134,7 +148,7 @@ public class FabricUIManagerTest {
public void testLayoutProgressBarAfterClonning() {
ProgressBarShadowNode node = new ProgressBarShadowNode();
node.setThemedContext(mThemedReactContext);
ProgressBarShadowNode clone = (ProgressBarShadowNode) node.mutableCopy();
ProgressBarShadowNode clone = (ProgressBarShadowNode) node.mutableCopy(randomInstanceHandle());
clone.calculateLayout();
}
@ -144,7 +158,7 @@ public class FabricUIManagerTest {
ReactShadowNode child = createViewNode();
node.addChildAt(child, 0);
ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildren(node, 0);
ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildren(node, randomInstanceHandle());
assertThat(clonedNode.getChildCount()).isZero();
assertSameFields(clonedNode, node);
@ -155,7 +169,7 @@ public class FabricUIManagerTest {
ReactShadowNode node = createViewNode();
ReadableNativeMap props = null; // TODO(ayc): Figure out how to create a Native map from tests.
ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewProps(node, props, 0);
ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewProps(node, props, randomInstanceHandle());
}
@Test
@ -163,7 +177,7 @@ public class FabricUIManagerTest {
ReactShadowNode node = createViewNode();
ReadableNativeMap props = null;
ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildrenAndProps(node, props, 0);
ReactShadowNode clonedNode = mFabricUIManager.cloneNodeWithNewChildrenAndProps(node, props, randomInstanceHandle());
assertThat(clonedNode.getChildCount()).isZero();
}
@ -221,10 +235,10 @@ public class FabricUIManagerTest {
new ReactRootView(RuntimeEnvironment.application.getApplicationContext());
int rootTag = mFabricUIManager.addRootView(rootView);
ReactShadowNode text =
mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null, mNextInstanceHandle++);
mFabricUIManager.createNode(0, ReactTextViewManager.REACT_CLASS, rootTag, null, randomInstanceHandle());
assertThat(text.isMeasureDefined()).isTrue();
ReactShadowNode textCopy = text.mutableCopy();
ReactShadowNode textCopy = text.mutableCopy(randomInstanceHandle());
assertThat(textCopy.isMeasureDefined()).isTrue();
textCopy.setStyleWidth(200);
@ -247,13 +261,13 @@ public class FabricUIManagerTest {
int rootTag = mFabricUIManager.addRootView(rootView);
String viewClass = ReactViewManager.REACT_CLASS;
ReactShadowNode aa = mFabricUIManager.createNode(2, viewClass, rootTag, null, mNextInstanceHandle++);
ReactShadowNode a = mFabricUIManager.createNode(3, viewClass, rootTag, null, mNextInstanceHandle++);
ReactShadowNode aa = mFabricUIManager.createNode(2, viewClass, rootTag, null, randomInstanceHandle());
ReactShadowNode a = mFabricUIManager.createNode(3, viewClass, rootTag, null, randomInstanceHandle());
mFabricUIManager.appendChild(a, aa);
ReactShadowNode bb = mFabricUIManager.createNode(4, viewClass, rootTag, null, mNextInstanceHandle++);
ReactShadowNode b = mFabricUIManager.createNode(5, viewClass, rootTag, null, mNextInstanceHandle++);
ReactShadowNode bb = mFabricUIManager.createNode(4, viewClass, rootTag, null, randomInstanceHandle());
ReactShadowNode b = mFabricUIManager.createNode(5, viewClass, rootTag, null, randomInstanceHandle());
mFabricUIManager.appendChild(b, bb);
ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null, mNextInstanceHandle++);
ReactShadowNode container = mFabricUIManager.createNode(6, viewClass, rootTag, null, randomInstanceHandle());
mFabricUIManager.appendChild(container, a);
mFabricUIManager.appendChild(container, b);
List<ReactShadowNode> childSet = mFabricUIManager.createChildSet(rootTag);

View File

@ -13,7 +13,7 @@ public class ReactShadowNodeTest {
@Test(expected = AssertionError.class)
public void testClonedInstance() {
TestReactShadowNode node = new TestReactShadowNode();
node.mutableCopy();
node.mutableCopy(node.getInstanceHandle());
}
private static class TestReactShadowNode extends ReactShadowNodeImpl {}