|
| 1 | +--- |
| 2 | +id: virtualview |
| 3 | +title: VirtualView ⚗️ |
| 4 | +--- |
| 5 | + |
| 6 | +:::important |
| 7 | +**This API is experimental.** Experimental APIs may contain bugs and are likely to change in a future version of React Native. Don't use them in production. |
| 8 | +::: |
| 9 | + |
| 10 | +`VirtualView` is a core component that behaves similar to [`View`](view). |
| 11 | + |
| 12 | +When it is the descendent of a [`ScrollView`](scrollview), it gains additional virtualization capabilities to reduce its memory footprint when obscured by the scroll viewport. |
| 13 | + |
| 14 | +```tsx |
| 15 | +<ScrollView> |
| 16 | + <VirtualView> |
| 17 | + <Text>Hello world!</Text> |
| 18 | + </VirtualView> |
| 19 | +</ScrollView> |
| 20 | +``` |
| 21 | + |
| 22 | +A `VirtualView` without an ancestor[`ScrollView`](scrollview) does not have any virtualization capabilities. |
| 23 | + |
| 24 | +## Virtualization |
| 25 | + |
| 26 | +When a `VirtualView` leaves the visible region of a [`ScrollView`](scrollview), it becomes hidden. When hidden, a `VirtualView` will cache its most recent layout and may unmount its children — a process called virtualization. |
| 27 | + |
| 28 | +When a `VirtualView` returns to the visible region of a [`ScrollView`](scrollview), it becomes visible. When visible, its children are _guaranteed_ to be rendered. This guarantee is maintained by blocking the main thread from rendering the next frame that would reveal the `VirtualView` until its children can be rendered. |
| 29 | + |
| 30 | +<img src="/docs/assets/d_virtualview_modes.svg" width="700" alt="Diagram of VirtualView modes and thresholds." /> |
| 31 | + |
| 32 | +:::note |
| 33 | +In future developments, a hidden `VirtualView` may instead render its children in an [`<Activity mode="hidden">`](https://react.dev/reference/react/Activity) to preserve state for as long as possible while balancing memory overhead. |
| 34 | +::: |
| 35 | + |
| 36 | +### Blocking the Main Thread |
| 37 | + |
| 38 | +This is the first time in React Native’s feature set where rendering a React component can block the main thread. This is a new capability enabled by the [New Architecture](/architecture/landing-page)! |
| 39 | + |
| 40 | +Blocking the main thread can provide a better user experience by preventing flashes of blank frames that sometimes occur when using components like [`FlatList`](flatlist). It can also enable better performance by using main thread priority, which is also typically run on higher performance cores. |
| 41 | + |
| 42 | +However, blocking the main thread also comes with tradeoffs. If an update operation, such as mounting the children of a `VirtualView`, takes too long to finish, it can now drop frames. Dropping more than a couple frames can lead to a worse user experience by making the app feel sluggish and non-responsive. Dropping too many frames may cause the operating system to display a modal indicating the app is not responsive, or it may even terminate your app! |
| 43 | + |
| 44 | +### Prerendering |
| 45 | + |
| 46 | +`VirtualView` enables you to benefit from main thread rendering while mitigating the disadvantages of dropped frames by rendering earlier before it is needed. This is called “prerendering”. |
| 47 | + |
| 48 | +By default, each `VirtualView` will prerender its children when it approaches the visible region of a [`ScrollView`](scrollview). When this happens, its children will be rendered on a background thread at a lower priority (using a [transition](https://react.dev/reference/react/startTransition)). This ensures that the main thread and React are available to handle other critical user interactions at a higher priority. |
| 49 | + |
| 50 | +:::note |
| 51 | +`VirtualView`'s prerender logic is not currently configurable. The algorithm for determining this is undergoing active design iteration and is likely to change in a future release. |
| 52 | +::: |
| 53 | + |
| 54 | +--- |
| 55 | + |
| 56 | +## Props |
| 57 | + |
| 58 | +### `children` |
| 59 | + |
| 60 | +Content to render inside this `VirtualView`. |
| 61 | + |
| 62 | +| Type | |
| 63 | +| ------------------------ | |
| 64 | +| [React Node](react-node) | |
| 65 | + |
| 66 | +--- |
| 67 | + |
| 68 | +### `onModeChange` |
| 69 | + |
| 70 | +Invoked when the `VirtualView` changes how it renders its children. |
| 71 | + |
| 72 | +If a callback is supplied, it may be invoked from different threads and priorities depending on the internal state change. This can be detected by checking the `mode` property on the event: |
| 73 | + |
| 74 | +- If `mode` is [`VirtualViewMode.Visible`](#virtualviewmode), the callback is being invoked from the main thread with immediate priority. |
| 75 | +- If `mode` is [`VirtualViewMode.Prerender`](#virtualviewmode) or [`VirtualViewMode.Hidden`](#virtualviewmode), the callback is being invoked from a background thread with transition priority. |
| 76 | + |
| 77 | +The callback will never be invoked consecutively with the same `mode` value. However, there are few guarantees about sequencing of events. Also, the callback may never be invoked with [`VirtualViewMode.Visible`](#virtualviewmode) even if it becomes visible, if the children were successfully prerendered. |
| 78 | + |
| 79 | +| Type | |
| 80 | +| -------------------------------------------------- | |
| 81 | +| `md ([ModeChangeEvent](#modechangeevent)) => void` | |
| 82 | + |
| 83 | +--- |
| 84 | + |
| 85 | +### `nativeID` |
| 86 | + |
| 87 | +An identifier for locating this view from native classes. |
| 88 | + |
| 89 | +| Type | |
| 90 | +| ------ | |
| 91 | +| string | |
| 92 | + |
| 93 | +--- |
| 94 | + |
| 95 | +### `style` |
| 96 | + |
| 97 | +| Type | |
| 98 | +| ------------------------------ | |
| 99 | +| [View Style](view-style-props) | |
| 100 | + |
| 101 | +--- |
| 102 | + |
| 103 | +## Type Definitions |
| 104 | + |
| 105 | +### `ModeChangeEvent` |
| 106 | + |
| 107 | +Argument supplied to [`onModeChange`](#onmodechange). |
| 108 | + |
| 109 | +| Type | |
| 110 | +| ------ | |
| 111 | +| object | |
| 112 | + |
| 113 | +**Properties:** |
| 114 | + |
| 115 | +| Name | Type | Description | |
| 116 | +| ------------- | ----------------------------------- | ------------------------------------------------------------------------------------------------- | |
| 117 | +| mode | [VirtualViewMode](#virtualviewmode) | New mode of the `VirtualView`. | |
| 118 | +| target | element | `VirtualView` emitting this event. | |
| 119 | +| targetRect | [Rect](rect) | Layout of `target` relative to the nearest ancestor `ScrollView`. | |
| 120 | +| thresholdRect | [Rect](rect) | Layout of the threshold that triggered this event, relative to the nearest ancestor `ScrollView`. | |
| 121 | + |
| 122 | +:::note |
| 123 | +For example, if a `VirtualView` enters the visible region of a [`ScrollView`](scrollview)... |
| 124 | + |
| 125 | +- `mode` would be [`VirtualViewMode.Visible`](#virtualviewmode) |
| 126 | +- `thresholdRect` would describe the visible viewport of the nearest ancestor [`ScrollView`](scrollview) |
| 127 | +- `targetRect` would be the layout of `target` that overlaps with `thresholdRect` (i.e. it is within the visible region of the [`ScrollView`](scrollview)) |
| 128 | + |
| 129 | +::: |
| 130 | + |
| 131 | +### `VirtualViewMode` |
| 132 | + |
| 133 | +Possible modes of a `VirtualView`. |
| 134 | + |
| 135 | +| Name | Value | Description | |
| 136 | +| --------- | ----- | ---------------------------------------------- | |
| 137 | +| Visible | `0` | Target view is visible. | |
| 138 | +| Prerender | `1` | Target view is hidden, but can be prerendered. | |
| 139 | +| Hidden | `2` | Target view is hidden. | |
| 140 | + |
| 141 | +--- |
| 142 | + |
| 143 | +## Static Methods |
| 144 | + |
| 145 | +### `createHiddenVirtualView()` |
| 146 | + |
| 147 | +```tsx |
| 148 | +static createHiddenVirtualView(height: number): typeof VirtualView; |
| 149 | +``` |
| 150 | + |
| 151 | +`VirtualView` initially renders its children as visible, even if it is initially obscured by an ancestor [`ScrollView`](scrollview). This is because when a component is initially rendered, the presence of an ancestor [`ScrollView`](scrollview) — let alone its size and scroll position — are unknown. |
| 152 | + |
| 153 | +For advanced use cases, `createHiddenVirtualView()` creates a component that renders an initially hidden `VirtualView` with the supplied estimated layout. |
| 154 | + |
| 155 | +```tsx |
| 156 | +const HiddenVirtualView = createHiddenVirtualView(100); |
| 157 | + |
| 158 | +<ScrollView> |
| 159 | + <HiddenVirtualView> |
| 160 | + <Text>Hello world!</Text> |
| 161 | + </HiddenVirtualView> |
| 162 | +</ScrollView>; |
| 163 | +``` |
| 164 | + |
| 165 | +**Parameters:** |
| 166 | + |
| 167 | +| Name | Type | Description | |
| 168 | +| ------------------------------------------------------- | ------ | ------------------------------------------------------ | |
| 169 | +| height <div class="label basic required">Required</div> | number | Estimated height of initially rendering `VirtualView`. | |
0 commit comments