mirror of
https://github.com/facebook/react-native.git
synced 2025-11-01 09:14:26 +00:00
Pass unflattened styles to reconciler (#45345)
Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45345 When React diffs props, it can can short-circuit nested objects if their object identity hasn't changed. Whenever we use `flattenStyle` we prevent this optimization from taking place. Changelog: [Internal] Reviewed By: dmytrorykun Differential Revision: D59518281 fbshipit-source-id: e88ca781ab4622b5342169f8f27b09f0515513b3
This commit is contained in:
committed by
Facebook GitHub Bot
parent
7e41ea4c9d
commit
d9d638c06b
@@ -9,6 +9,7 @@
|
||||
*/
|
||||
|
||||
import type {HostComponent} from '../../Renderer/shims/ReactNativeTypes';
|
||||
import type {____TextStyle_Internal as TextStyleInternal} from '../../StyleSheet/StyleSheetTypes';
|
||||
import type {
|
||||
PressEvent,
|
||||
ScrollEvent,
|
||||
@@ -1534,10 +1535,18 @@ function InternalTextInput(props: Props): React.Node {
|
||||
};
|
||||
}
|
||||
|
||||
let style = flattenStyle<TextStyleProp>(props.style);
|
||||
if (typeof style?.fontWeight === 'number') {
|
||||
// $FlowFixMe
|
||||
style = [style, {fontWeight: style.fontWeight.toString()}];
|
||||
// Keep the original (potentially nested) style when possible, as React can diff these more efficiently
|
||||
let _style = props.style;
|
||||
const flattenedStyle = flattenStyle<TextStyleProp>(props.style);
|
||||
if (typeof flattenedStyle?.fontWeight === 'number') {
|
||||
_style = [
|
||||
_style,
|
||||
{
|
||||
fontWeight:
|
||||
// $FlowFixMe[incompatible-cast]
|
||||
(flattenedStyle.fontWeight.toString(): TextStyleInternal['fontWeight']),
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
@@ -1548,10 +1557,10 @@ function InternalTextInput(props: Props): React.Node {
|
||||
|
||||
const useMultilineDefaultStyle =
|
||||
props.multiline === true &&
|
||||
(style == null ||
|
||||
(style.padding == null &&
|
||||
style.paddingVertical == null &&
|
||||
style.paddingTop == null));
|
||||
(flattenedStyle == null ||
|
||||
(flattenedStyle.padding == null &&
|
||||
flattenedStyle.paddingVertical == null &&
|
||||
flattenedStyle.paddingTop == null));
|
||||
|
||||
textInput = (
|
||||
<RCTTextInputView
|
||||
@@ -1578,7 +1587,7 @@ function InternalTextInput(props: Props): React.Node {
|
||||
selectionColor={selectionColor}
|
||||
style={StyleSheet.compose(
|
||||
useMultilineDefaultStyle ? styles.multilineDefault : null,
|
||||
style,
|
||||
_style,
|
||||
)}
|
||||
text={text}
|
||||
/>
|
||||
@@ -1645,7 +1654,7 @@ function InternalTextInput(props: Props): React.Node {
|
||||
onScroll={_onScroll}
|
||||
onSelectionChange={_onSelectionChange}
|
||||
placeholder={placeholder}
|
||||
style={style}
|
||||
style={_style}
|
||||
text={text}
|
||||
textBreakStrategy={props.textBreakStrategy}
|
||||
/>
|
||||
|
||||
@@ -150,24 +150,20 @@ let BaseImage: AbstractImageAndroid = React.forwardRef(
|
||||
);
|
||||
}
|
||||
|
||||
let style;
|
||||
let style: ImageStyleProp;
|
||||
let sources;
|
||||
if (Array.isArray(source)) {
|
||||
style = flattenStyle<ImageStyleProp>([styles.base, props.style]);
|
||||
style = [styles.base, props.style];
|
||||
sources = source;
|
||||
} else {
|
||||
const {uri} = source;
|
||||
const width = source.width ?? props.width;
|
||||
const height = source.height ?? props.height;
|
||||
style = flattenStyle<ImageStyleProp>([
|
||||
{width, height},
|
||||
styles.base,
|
||||
props.style,
|
||||
]);
|
||||
sources = [source];
|
||||
if (uri === '') {
|
||||
console.warn('source.uri should not be an empty string');
|
||||
}
|
||||
const width = source.width ?? props.width;
|
||||
const height = source.height ?? props.height;
|
||||
style = [{width, height}, styles.base, props.style];
|
||||
sources = [source];
|
||||
}
|
||||
|
||||
const {height, width, ...restProps} = props;
|
||||
@@ -203,11 +199,10 @@ let BaseImage: AbstractImageAndroid = React.forwardRef(
|
||||
},
|
||||
};
|
||||
|
||||
const objectFit = style?.objectFit
|
||||
? convertObjectFitToResizeMode(style.objectFit)
|
||||
: null;
|
||||
const flattenedStyle = flattenStyle<ImageStyleProp>(style);
|
||||
const objectFit = convertObjectFitToResizeMode(flattenedStyle?.objectFit);
|
||||
const resizeMode =
|
||||
objectFit || props.resizeMode || style?.resizeMode || 'cover';
|
||||
objectFit || props.resizeMode || flattenedStyle?.resizeMode || 'cover';
|
||||
|
||||
const actualRef = useWrapRefWithImageAttachedCallbacks(forwardedRef);
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {ImageStyle, ImageStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {ImageStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {RootTag} from '../Types/RootTagTypes';
|
||||
import type {AbstractImageIOS, ImageIOS} from './ImageTypes.flow';
|
||||
import type {ImageSize} from './NativeImageLoaderAndroid';
|
||||
@@ -112,38 +112,27 @@ let BaseImage: AbstractImageIOS = React.forwardRef((props, forwardedRef) => {
|
||||
height: undefined,
|
||||
};
|
||||
|
||||
let style: ImageStyleProp;
|
||||
let sources;
|
||||
let style: ImageStyle;
|
||||
|
||||
if (Array.isArray(source)) {
|
||||
style =
|
||||
flattenStyle<ImageStyleProp>([styles.base, props.style]) ||
|
||||
({}: ImageStyle);
|
||||
style = [styles.base, props.style];
|
||||
sources = source;
|
||||
} else {
|
||||
const {uri} = source;
|
||||
const width = source.width ?? props.width;
|
||||
const height = source.height ?? props.height;
|
||||
style =
|
||||
flattenStyle<ImageStyleProp>([
|
||||
{width, height},
|
||||
styles.base,
|
||||
props.style,
|
||||
]) || ({}: ImageStyle);
|
||||
sources = [source];
|
||||
|
||||
if (uri === '') {
|
||||
console.warn('source.uri should not be an empty string');
|
||||
}
|
||||
const width = source.width ?? props.width;
|
||||
const height = source.height ?? props.height;
|
||||
style = [{width, height}, styles.base, props.style];
|
||||
sources = [source];
|
||||
}
|
||||
|
||||
const objectFit =
|
||||
style.objectFit != null
|
||||
? convertObjectFitToResizeMode(style.objectFit)
|
||||
: null;
|
||||
const flattenedStyle = flattenStyle<ImageStyleProp>(style);
|
||||
const objectFit = convertObjectFitToResizeMode(flattenedStyle?.objectFit);
|
||||
const resizeMode =
|
||||
objectFit || props.resizeMode || style.resizeMode || 'cover';
|
||||
const tintColor = props.tintColor ?? style.tintColor;
|
||||
objectFit || props.resizeMode || flattenedStyle?.resizeMode || 'cover';
|
||||
const tintColor = props.tintColor ?? flattenedStyle?.tintColor;
|
||||
|
||||
if (props.children != null) {
|
||||
throw new Error(
|
||||
|
||||
+9
-9
@@ -10,13 +10,13 @@
|
||||
|
||||
type ResizeMode = 'cover' | 'contain' | 'stretch' | 'repeat' | 'center';
|
||||
|
||||
export function convertObjectFitToResizeMode(objectFit: string): ResizeMode {
|
||||
const objectFitMap = {
|
||||
contain: 'contain',
|
||||
cover: 'cover',
|
||||
fill: 'stretch',
|
||||
'scale-down': 'contain',
|
||||
};
|
||||
// $FlowFixMe[invalid-computed-prop]
|
||||
return objectFitMap[objectFit];
|
||||
const objectFitMap: {[string]: ResizeMode} = {
|
||||
contain: 'contain',
|
||||
cover: 'cover',
|
||||
fill: 'stretch',
|
||||
'scale-down': 'contain',
|
||||
};
|
||||
|
||||
export function convertObjectFitToResizeMode(objectFit: ?string): ?ResizeMode {
|
||||
return objectFit != null ? objectFitMap[objectFit] : undefined;
|
||||
}
|
||||
|
||||
@@ -31,11 +31,16 @@ exports[`Image should render as <RCTImageView> when not mocked 1`] = `
|
||||
]
|
||||
}
|
||||
style={
|
||||
Object {
|
||||
"height": undefined,
|
||||
"overflow": "hidden",
|
||||
"width": undefined,
|
||||
}
|
||||
Array [
|
||||
Object {
|
||||
"height": undefined,
|
||||
"width": undefined,
|
||||
},
|
||||
Object {
|
||||
"overflow": "hidden",
|
||||
},
|
||||
undefined,
|
||||
]
|
||||
}
|
||||
/>
|
||||
`;
|
||||
|
||||
+7
-6
@@ -8,6 +8,7 @@
|
||||
* @format
|
||||
*/
|
||||
|
||||
import type {TextStyleProp} from '../StyleSheet/StyleSheet';
|
||||
import type {____TextStyle_Internal as TextStyleInternal} from '../StyleSheet/StyleSheetTypes';
|
||||
import type {PressEvent} from '../Types/CoreEventTypes';
|
||||
import type {NativeTextProps} from './TextNativeComponent';
|
||||
@@ -133,7 +134,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
|
||||
|
||||
let _selectable = selectable;
|
||||
|
||||
let processedStyle: ?TextStyleInternal = flattenStyle(_style);
|
||||
let processedStyle = flattenStyle<TextStyleProp>(_style);
|
||||
if (processedStyle != null) {
|
||||
let overrides: ?{...TextStyleInternal} = null;
|
||||
if (typeof processedStyle.fontWeight === 'number') {
|
||||
@@ -158,7 +159,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
|
||||
|
||||
if (overrides != null) {
|
||||
// $FlowFixMe[incompatible-type]
|
||||
processedStyle = [processedStyle, overrides];
|
||||
_style = [_style, overrides];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -178,7 +179,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
|
||||
numberOfLines: _numberOfLines,
|
||||
selectable: _selectable,
|
||||
selectionColor: _selectionColor,
|
||||
style: processedStyle,
|
||||
style: _style,
|
||||
disabled: disabled,
|
||||
children,
|
||||
}}
|
||||
@@ -212,7 +213,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
|
||||
ref={forwardedRef}
|
||||
selectable={_selectable}
|
||||
selectionColor={_selectionColor}
|
||||
style={processedStyle}
|
||||
style={_style}
|
||||
disabled={disabled}>
|
||||
{children}
|
||||
</NativeVirtualText>
|
||||
@@ -256,7 +257,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
|
||||
numberOfLines: _numberOfLines,
|
||||
selectable: _selectable,
|
||||
selectionColor: _selectionColor,
|
||||
style: processedStyle,
|
||||
style: _style,
|
||||
children,
|
||||
}}
|
||||
textPressabilityProps={{
|
||||
@@ -291,7 +292,7 @@ const Text: React.AbstractComponent<TextProps, TextForwardRef> =
|
||||
ref={forwardedRef}
|
||||
selectable={_selectable}
|
||||
selectionColor={_selectionColor}
|
||||
style={processedStyle}>
|
||||
style={_style}>
|
||||
{children}
|
||||
</NativeText>
|
||||
);
|
||||
|
||||
@@ -5002,8 +5002,8 @@ export type { ImageProps } from \\"./ImageProps\\";
|
||||
exports[`public API should not change unintentionally Libraries/Image/ImageUtils.js 1`] = `
|
||||
"type ResizeMode = \\"cover\\" | \\"contain\\" | \\"stretch\\" | \\"repeat\\" | \\"center\\";
|
||||
declare export function convertObjectFitToResizeMode(
|
||||
objectFit: string
|
||||
): ResizeMode;
|
||||
objectFit: ?string
|
||||
): ?ResizeMode;
|
||||
"
|
||||
`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user