mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
VirtualView: Configurable Hidden Layout (#53571)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/53571 Changes `VirtualView` so that its layout when hidden can be configured by call sites. Previously, it was hardcoded to only retain the last known height. However, this logic only works for `VirtualView` children oriented in a column layout. This change enables the use of `VirtualView` in more flexible abstractions that require different hidden styles (e.g. row or grid orientations). Also, this changes the default behavior to set `minWidth` and `minHeight`, so that the default behavior is more general and more likely to work in a reasonable manner in more use cases. NOTE: Ideally, we would be able to default to using `flexBasis` instead. However, the `hiddenStyle` function receives a `Rect` and does not know whether the parent's flex direction is row or column to influence whether to use `targetRect.width` or `targetRect.height`. This is an opportunity for future improvement. Changelog: [Internal] Reviewed By: lunaleaps Differential Revision: D81344126 fbshipit-source-id: 33d9e81601b671059f97b4590816243cbd24734a
This commit is contained in:
committed by
Facebook GitHub Bot
parent
1604232e8d
commit
d6ed32f8d6
@@ -56,6 +56,7 @@ const VirtualViewNativeComponent: typeof VirtualViewClassicNativeComponent =
|
||||
|
||||
type VirtualViewComponent = component(
|
||||
children?: React.Node,
|
||||
hiddenStyle?: (targetRect: Rect) => ViewStyleProp,
|
||||
nativeID?: string,
|
||||
ref?: ?React.RefSetter<React.ElementRef<typeof VirtualViewNativeComponent>>,
|
||||
style?: ?ViewStyleProp,
|
||||
@@ -63,16 +64,21 @@ type VirtualViewComponent = component(
|
||||
removeClippedSubviews?: boolean,
|
||||
);
|
||||
|
||||
type HiddenHeight = number;
|
||||
const NotHidden = null;
|
||||
type HiddenStyle = Exclude<ViewStyleProp, typeof NotHidden>;
|
||||
|
||||
type State = HiddenHeight | typeof NotHidden;
|
||||
type State = HiddenStyle | typeof NotHidden;
|
||||
|
||||
function defaultHiddenStyle(targetRect: Rect): ViewStyleProp {
|
||||
return {minHeight: targetRect.height, minWidth: targetRect.width};
|
||||
}
|
||||
|
||||
function createVirtualView(initialState: State): VirtualViewComponent {
|
||||
const initialHidden = initialState !== NotHidden;
|
||||
|
||||
component VirtualView(
|
||||
children?: React.Node,
|
||||
hiddenStyle: (targetRect: Rect) => ViewStyleProp = defaultHiddenStyle,
|
||||
nativeID?: string,
|
||||
ref?: ?React.RefSetter<React.ElementRef<typeof VirtualViewNativeComponent>>,
|
||||
style?: ?ViewStyleProp,
|
||||
@@ -112,9 +118,8 @@ function createVirtualView(initialState: State): VirtualViewComponent {
|
||||
});
|
||||
}
|
||||
VirtualViewMode.Hidden => {
|
||||
const {height} = event.nativeEvent.targetRect;
|
||||
startTransition(() => {
|
||||
setState(height as HiddenHeight);
|
||||
setState(hiddenStyle(event.nativeEvent.targetRect) ?? {});
|
||||
emitModeChange?.();
|
||||
});
|
||||
}
|
||||
@@ -134,9 +139,7 @@ function createVirtualView(initialState: State): VirtualViewComponent {
|
||||
}
|
||||
style={
|
||||
isHidden
|
||||
? StyleSheet.compose(style, {
|
||||
height: Math.abs(nullthrows(state) as HiddenHeight),
|
||||
})
|
||||
? StyleSheet.compose(style, nullthrows(state) as HiddenStyle)
|
||||
: style
|
||||
}
|
||||
onModeChange={handleModeChange}>
|
||||
@@ -159,8 +162,10 @@ function createVirtualView(initialState: State): VirtualViewComponent {
|
||||
|
||||
export default createVirtualView(NotHidden) as VirtualViewComponent;
|
||||
|
||||
export function createHiddenVirtualView(height: number): VirtualViewComponent {
|
||||
return createVirtualView(height as HiddenHeight);
|
||||
export function createHiddenVirtualView(
|
||||
style: ViewStyleProp,
|
||||
): VirtualViewComponent {
|
||||
return createVirtualView((style ?? {}) as HiddenStyle);
|
||||
}
|
||||
|
||||
export const _logs: {states?: Array<State>} = {};
|
||||
|
||||
+12
-12
@@ -119,19 +119,19 @@ describe('mode changes', () => {
|
||||
});
|
||||
|
||||
describe('styles', () => {
|
||||
test('does not set height when visible', () => {
|
||||
test('does not set styles when visible', () => {
|
||||
const root = Fantom.createRoot();
|
||||
|
||||
Fantom.runTask(() => {
|
||||
root.render(<VirtualView />);
|
||||
});
|
||||
|
||||
expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual(
|
||||
<rn-virtualView />,
|
||||
);
|
||||
expect(
|
||||
root.getRenderedOutput({props: ['minHeight', 'minWidth']}).toJSX(),
|
||||
).toEqual(<rn-virtualView />);
|
||||
});
|
||||
|
||||
test('does not set height when prerendered', () => {
|
||||
test('does not set styles when prerendered', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const viewRef = createRef<React.RefOf<VirtualView>>();
|
||||
|
||||
@@ -141,12 +141,12 @@ describe('styles', () => {
|
||||
|
||||
dispatchModeChangeEvent(viewRef.current, VirtualViewMode.Prerender);
|
||||
|
||||
expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual(
|
||||
<rn-virtualView />,
|
||||
);
|
||||
expect(
|
||||
root.getRenderedOutput({props: ['minHeight', 'minWidth']}).toJSX(),
|
||||
).toEqual(<rn-virtualView />);
|
||||
});
|
||||
|
||||
test('sets height when hidden', () => {
|
||||
test('sets styles when hidden', () => {
|
||||
const root = Fantom.createRoot();
|
||||
const viewRef = createRef<React.RefOf<VirtualView>>();
|
||||
|
||||
@@ -156,9 +156,9 @@ describe('styles', () => {
|
||||
|
||||
dispatchModeChangeEvent(viewRef.current, VirtualViewMode.Hidden);
|
||||
|
||||
expect(root.getRenderedOutput({props: ['height']}).toJSX()).toEqual(
|
||||
<rn-virtualView height="100.000000" />,
|
||||
);
|
||||
expect(
|
||||
root.getRenderedOutput({props: ['minHeight', 'minWidth']}).toJSX(),
|
||||
).toEqual(<rn-virtualView minHeight="100.000000" minWidth="100.000000" />);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user