react-native
                                
                                 react-native copied to clipboard
                                
                                    react-native copied to clipboard
                            
                            
                            
                        Basic implementation of IntersectionObserver
Summary:
This adds a basic implementation of IntersectionObserver. This will not be available yet and is only compatible with the new React Native architecture. This shouldn't show up in the changelog until we're ready to enable this in some form.
Changelog: [Internal]
Context
This implements a basic version of the IntersectionObserver API (as defined on the Web) for React Native.
The motivation for this is supporting several use cases that are not possible in React Native at the moment, most importantly:
- Tracking paint times for elements in the screen.
- Tracking precise visibility of elements in the screen outside the context of a VirtualizedList(with an even better precision and control).
Implementation details
This API is implemented as a native module that registers a mount hook in Fabric. Whenever there's a mount (an update to the UI of the host platform) we check for intersections in the shadow tree. The shadow tree contains information about the representation of the UI in a given time (including scroll position), which we use as source of truth for this in a cross-platform fashion. We rely on the fact that scroll position is updated regularly in the shadow tree to provide an up-to-date view into the UI.
This implementation is completely cross-platform. The only platform-specific part is the report of mounts in mount hooks from the host platform to Fabric.
This API uses a centralized entity in JS and native to handle registration of observers and dispatch of notifications. The dispatch the notifications for all observers in the same callback so we can easily change the sequencing of events easily (for example, we can change this to use microtasks when they're available in RN).
Known limitations
- Timestamps are generally accurate for paint (as we report mounts right after they happen in the host platform), but state updates (like scroll) are reported with a slight delay.
- In regular rendering, we first update the shadow tree and then mount it (paint), which is generally precise. In state updates, the UI is updated first and then the shadow tree is updated. In this case, we're not correctly reporting the timestamp of the scroll event (which we should be using) but the timestamp of when the update is processed. We'll fix this in a following diff.
 
- The IntersectionObserver API has a concept of initial notification. This is a mechanism to report the initial state of an observed target. If we start observing a target when it's added to the tree but before it's painted, this initial notification is supposed to provide initial paint time (which is important for performance measurements). This implements some logic to handle that correctly (we check if there is a pending transaction) but it's currently unreliable:
- React Native does not currently block paint on microtasks or layout effects, so setting up an observer in these stages could have race conditions with actual mount. If mount happens before the observation is started, the initial notification doesn't report initial time but observation time. If mount happens after, the initial notification should be fine (except in some cases on Android, see the next point).
- On Android, we have a push model to send mutations to the host platform, we means we consume transactions after commit, not immediately before mount. This breaks this logic and we need to figure out a solution in a following diff.
 
Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
| Platform | Engine | Arch | Size (bytes) | Diff | 
|---|---|---|---|---|
| android | hermes | arm64-v8a | 8,975,105 | +1,033 | 
| android | hermes | armeabi-v7a | 8,236,127 | +863 | 
| android | hermes | x86 | 9,488,993 | +1,252 | 
| android | hermes | x86_64 | 9,331,365 | +1,163 | 
| android | jsc | arm64-v8a | 9,535,896 | +1,031 | 
| android | jsc | armeabi-v7a | 8,674,245 | +855 | 
| android | jsc | x86 | 9,620,661 | +1,262 | 
| android | jsc | x86_64 | 9,867,137 | +1,157 | 
Base commit: 7e934947d752d1f49a8d848209a7aaf02cdb700b Branch: main
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was exported from Phabricator. Differential Revision: D45278720
This pull request was successfully merged by @rubennorte in 387bd70e49f67d310764dd23a9e6edb93cc00b73.
When will my fix make it into a release? | Upcoming Releases