Skip to content

Commit d18f1f7

Browse files
Jack Popefacebook-github-bot
authored andcommitted
Enable Fragment Refs for intersection observers on Fabric (#52474)
Summary: Pull Request resolved: #52474 1. Enables the feature flags for fragment refs on fbsource 2. Adds a test with Fantom for usage of `FragmentInstance#observeUsing` and `FragmentInstance#unobserveUsing`. 3. Exposes the `ReactFragmentInstance` type with the common methods that are used on native. We can override the DOM only methods in www libdefs. Changelog: [Internal] Reviewed By: rubennorte Differential Revision: D74326262 fbshipit-source-id: e35ee45b23179ad3ba5527763567c9b04c127eff
1 parent 23f3bf9 commit d18f1f7

3 files changed

Lines changed: 85 additions & 2 deletions

File tree

packages/react-native/Libraries/LogBox/__tests__/LogBox-itest.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,7 +802,7 @@ describe('LogBox', () => {
802802
expect(logBox.getNotificationUI()).toEqual({
803803
count: '!',
804804
message:
805-
'Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.',
805+
'Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key`, `ref`, and `children` props.',
806806
});
807807

808808
// Open LogBox.
@@ -817,7 +817,7 @@ describe('LogBox', () => {
817817
// This seems like a bug, should be "Render Error".
818818
title: 'Console Error',
819819
message:
820-
'Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key` and `children` props.',
820+
'Invalid prop `invalid` supplied to `React.Fragment`. React.Fragment can only have `key`, `ref`, and `children` props.',
821821
componentStackFrames: ['<TestComponent />'],
822822
isDismissable: true,
823823
});
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/**
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*
7+
* @flow strict-local
8+
* @format
9+
* @oncall react_native
10+
*/
11+
12+
import '@react-native/fantom/src/setUpDefaultReactNativeEnvironment';
13+
14+
import * as Fantom from '@react-native/fantom';
15+
import * as React from 'react';
16+
import {View} from 'react-native';
17+
import setUpIntersectionObserver from 'react-native/src/private/setup/setUpIntersectionObserver';
18+
19+
setUpIntersectionObserver();
20+
21+
describe('Fragment Refs', () => {
22+
describe('observers', () => {
23+
it('attaches intersection observers to children', () => {
24+
let logs: Array<string> = [];
25+
const root = Fantom.createRoot({
26+
viewportHeight: 1000,
27+
viewportWidth: 1000,
28+
});
29+
// $FlowFixMe[cannot-resolve-name] oss doesn't have this
30+
const observer = new IntersectionObserver(entries => {
31+
entries.forEach(entry => {
32+
if (entry.isIntersecting) {
33+
logs.push(`show:${entry.target.id}`);
34+
} else {
35+
logs.push(`hide:${entry.target.id}`);
36+
}
37+
});
38+
});
39+
function Test({showB}: {showB: boolean}) {
40+
// $FlowFixMe[cannot-resolve-name] oss doesn't have this
41+
const fragmentRef = React.useRef<null | ReactFragmentInstance>(null);
42+
React.useEffect(() => {
43+
fragmentRef.current?.observeUsing(observer);
44+
const lastRefValue = fragmentRef.current;
45+
return () => {
46+
lastRefValue?.unobserveUsing(observer);
47+
};
48+
}, []);
49+
return (
50+
<View nativeID="parent">
51+
{/* $FlowFixMe oss doesn't have this */}
52+
<React.Fragment ref={fragmentRef}>
53+
<View style={{width: 100, height: 100}} nativeID="childA" />
54+
{showB && (
55+
<View style={{width: 100, height: 100}} nativeID="childB" />
56+
)}
57+
</React.Fragment>
58+
</View>
59+
);
60+
}
61+
62+
Fantom.runTask(() => {
63+
root.render(<Test showB={false} />);
64+
});
65+
expect(logs).toEqual(['show:childA']);
66+
67+
// Reveal child and expect it to be observed and intersecting
68+
logs = [];
69+
Fantom.runTask(() => {
70+
root.render(<Test showB={true} />);
71+
});
72+
expect(logs).toEqual(['show:childB']);
73+
74+
// Hide child and expect it to still be observed, no longer intersecting
75+
logs = [];
76+
Fantom.runTask(() => {
77+
root.render(<Test showB={false} />);
78+
});
79+
expect(logs).toEqual(['hide:childB']);
80+
});
81+
});
82+
});

private/react-native-fantom/runtime/mocks/ReactNativeInternalFeatureFlags.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,5 @@ module.exports = {
1515
// and have predictable memory model.
1616
// See https://github.com/facebook/react/pull/33161 for details.
1717
enableEagerAlternateStateNodeCleanup: true,
18+
enableFragmentRefs: true,
1819
};

0 commit comments

Comments
 (0)