Skip to content

Add documentation for passChildrenWhenCloning feature #51447

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

Closed
wants to merge 2 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions __docs__/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ TODO: Explain the different components of React Native at a high level.
- UI / Fabric
- Events
- Shadow Tree Lifecycle
- [Runtime Shadow Node Reference Update](../packages/react-native/ReactCommon/react/renderer/core/__docs__/RSNRU.md)
- [passChildrenWhenCloningPersistedNodes](../packages/react-native/ReactCommon/react/renderer/core/__docs__/passChildrenWhenCloning.md)
- Layout
- Mounting
- Native Modules / TurboModules
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Runtime Shadow Node Reference Updates

[🏠 Home](../../../../../../../__docs__/README.md)

RSNRU (short for Runtime Shadow Node Reference Updates) is an update mechanism
for Shadow Node references held by the React renderer. The feature guarantees
that the React renderer holds onto the latest revision of the Shadow Node after
it was cloned internally behind the React renderer's back.

This feature improves layout performance by maximizing the use of the layout
cache stored on the Shadow Node instances. Maintaining a reference to the latest
revision of Shadow Node instances cloned internally after a commit also improves
the freshness of native state held on the Shadow Node instance.

## 🚀 Usage

RSNRU is enabled by default in single threaded mode. The JS Runtime thread is
marked as the thread allowing Shadow Node refernce updates to happen.

Threads can be marked for allowing RSNRU by calling the ShadowNode's
`setUseRuntimeShadowNodeReferenceUpdateOnThread` function from the thread.

If the `updateRuntimeShadowNodeReferencesOnCommit` feature flag is enabled,
RSNRU will run on commit and propagate internal clones from any thread, ignoring
the `setUseRuntimeShadowNodeReferenceUpdateOnThread` setting.

## 📐 Design

![RSNRU in React Native](./RSNRU.excalidraw.svg)

The React renderer running within the JS Runtime communicates with React Native
through operations running on pointers to ShadowNode instances created by React
Native. The renderer will submit requests for creating, mutating and cloning
ShadowNode instances. These operations take ShadowNode pointers as input (for
creation and mutation) and returns the resulting ShadowNode as a pointers to the
ShadowNode instance. Any operation requested by the renderer does not trigger
RSNRU since the renderer receives the cloned instance as a result for the call
to React Native.

RSNRU modifies the returned response by returning a wrapper around the
ShadowNode pointer and storing a reference to this wrapper on the ShadowNode
instance. This mechanism enables React Native to update the wrapper to point to
new clone of the ShadowNode without needing to call into the JS Runtime.

When the renderer commits a rendered tree, React Native will process the commit
by running state updates and the layout of the tree of ShadowNode instance.
Because ShadowNode instance are immutable, any change resulting from these
operations will lead to the ShadowNode being cloned so that the mutation can be
applied to the cloned instance.

Whenever ShadowNode cloning happens outside of a direct renderer request, RSNRU
will check if the ShadowNode is referenced by the renderer within the JS Runtime
by checking if the ShadowNode instance holds a reference to a wrapper. If a
wrapper is present, it will be updated with the newly cloned instance so that
the renderer would hold a reference to that new revision of the ShadowNode
instance.

When the renderer commits the next renderer tree, React Native will interact
with ShadowNode instances that hold the native state and layout information
evaluated during the last commit. This improves the "freshness" of the
ShadowNode layout cache and improves the layout pass.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# Runtime Shadow Node Reference Updates

[🏠 Home](../../../../../../../__docs__/README.md)

The `passChildrenWhenCloningPersistedNodes` feature improves rendering
performance for use cases where cloning of Shadow Nodes holding a large number
of children is frequent. A typical example of these are ScrollView components
holding large lists. The feature improves layout performance by reducing the
need to invalidate the layout information held by the cloned Shadow Node.

## 🚀 Usage

The features is controlled by the `passChildrenWhenCloningPersistedNodes` flag
defined in the `ReactNativeInternalFeatureFlags` file. Seeting the feature flag
before the React renderer is initialized will enable the feature.

## 📐 Design

![passChildrenWhenCloningPersistedNodes in React Native](./passChildrenWhenCloning.excalidraw.svg)

When the React renderer needs to clone a node that represents a host component
and thus has a corresponding ShadowNode instance, the process follows these
steps:

- Clone the ShadowNode
- Traverse the node's descendants to find all first level host components
- Whenever a host component is seen, append it to the newly cloned ShadowNode
instance

Most ShadowNode instances hold layout data and are represented by a
YogaLayoutableShadowNode. These nodes are responsible for keeping the yoga tree
updated and holding the final layout data for the native view that the
ShadowNode represents.

Any modification of a YogaLayoutableShadowNode will mark the node as dirty and
requiring layout when committed. Appending a child node to a
YogaLayoutableShadowNode is considered as a modification. Meaning that whenever
the React renderer needs to clone a ShadowNode that has direct children, it will
be marked as having a dirty layout when the children will be appended back to
the cloned instance.

The `passChildrenWhenCloningPersistedNodes` feature collects all children that
need to be appended to the ShadowNode after cloning in a set. This set is being
passed to the ShadowNode clone call which in turn will append back the nodes
directly during the cloning. This removes the need to append the children one by
one after cloning and bypasses the node dirtying that is involved with this type
of mutation.

The clone implementation of the YogaLayoutableShadowNode will compare the
previous set of children with the new set. If both sets have the same size and
each node has equivalent styling, the cloned node is not being dirtied for
layout. This allows for improving the layout data re-use on subsequent renders.
Loading