From 12b85d06e5cb2bfd0eae061930565f680f163bba Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Fri, 3 Jul 2026 13:50:56 +0200 Subject: [PATCH 1/2] perf(js): memoize sharedProps in EnrichedMarkdownText The sharedProps object passed to the native component was recreated on every render, forcing native prop diffing even when no values changed. Wrap it in useMemo with precise dependencies so parent re-renders that don't change any markdown-related props skip the native bridge entirely. Co-authored-by: Cursor --- .../src/native/EnrichedMarkdownText.tsx | 86 +++++++++++++------ 1 file changed, 59 insertions(+), 27 deletions(-) diff --git a/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx b/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx index 7ca4a56ed..2bd2a378a 100644 --- a/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx +++ b/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx @@ -263,33 +263,65 @@ export const EnrichedMarkdownText = ({ [accessibilityLabels] ); - const sharedProps = { - markdown, - markdownStyle: normalizedStyle, - onLinkPress: handleLinkPress, - onLinkLongPress: handleLinkLongPress, - onTaskListItemPress: handleTaskListItemPress, - enableLinkPreview: onLinkLongPress == null && (enableLinkPreview ?? true), - selectable, - md4cFlags: normalizedMd4cFlags, - allowFontScaling, - maxFontSizeMultiplier, - allowTrailingMargin, - streamingAnimation, - streamingConfig: normalizedStreamingConfig, - spoilerOverlay, - style: containerStyle, - contextMenuItems: nativeContextMenuItems, - selectionMenuConfig: normalizedSelectionMenuConfig, - accessibilityLabels: resolvedAccessibilityLabels, - onContextMenuItemPress: handleContextMenuItemPress, - selectionColor, - selectionHandleColor, - textBreakStrategy, - lineBreakStrategyIOS, - writingDirection, - ...rest, - }; + const enableLinkPreviewResolved = + onLinkLongPress == null && (enableLinkPreview ?? true); + + const sharedProps = useMemo( + () => ({ + markdown, + markdownStyle: normalizedStyle, + onLinkPress: handleLinkPress, + onLinkLongPress: handleLinkLongPress, + onTaskListItemPress: handleTaskListItemPress, + enableLinkPreview: enableLinkPreviewResolved, + selectable, + md4cFlags: normalizedMd4cFlags, + allowFontScaling, + maxFontSizeMultiplier, + allowTrailingMargin, + streamingAnimation, + streamingConfig: normalizedStreamingConfig, + spoilerOverlay, + style: containerStyle, + contextMenuItems: nativeContextMenuItems, + selectionMenuConfig: normalizedSelectionMenuConfig, + accessibilityLabels: resolvedAccessibilityLabels, + onContextMenuItemPress: handleContextMenuItemPress, + selectionColor, + selectionHandleColor, + textBreakStrategy, + lineBreakStrategyIOS, + writingDirection, + ...rest, + }), + [ + markdown, + normalizedStyle, + handleLinkPress, + handleLinkLongPress, + handleTaskListItemPress, + enableLinkPreviewResolved, + selectable, + normalizedMd4cFlags, + allowFontScaling, + maxFontSizeMultiplier, + allowTrailingMargin, + streamingAnimation, + normalizedStreamingConfig, + spoilerOverlay, + containerStyle, + nativeContextMenuItems, + normalizedSelectionMenuConfig, + resolvedAccessibilityLabels, + handleContextMenuItemPress, + selectionColor, + selectionHandleColor, + textBreakStrategy, + lineBreakStrategyIOS, + writingDirection, + rest, + ] + ); if (flavor === 'github') { return ; From 67b9356fcd05f210d7dde205228e9cacea431261 Mon Sep 17 00:00:00 2001 From: Gregory Moskaliuk Date: Fri, 3 Jul 2026 14:19:00 +0200 Subject: [PATCH 2/2] fix: exclude rest spread from useMemo to preserve stable identity rest comes from parameter destructuring and gets a new object identity on every render, which invalidated the memo every time. Move rest out of the memoized object and spread it at the JSX render site instead. Co-authored-by: Cursor --- .../src/native/EnrichedMarkdownText.tsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx b/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx index 2bd2a378a..40bd0f092 100644 --- a/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx +++ b/packages/react-native-enriched-markdown/src/native/EnrichedMarkdownText.tsx @@ -292,7 +292,6 @@ export const EnrichedMarkdownText = ({ textBreakStrategy, lineBreakStrategyIOS, writingDirection, - ...rest, }), [ markdown, @@ -319,15 +318,14 @@ export const EnrichedMarkdownText = ({ textBreakStrategy, lineBreakStrategyIOS, writingDirection, - rest, ] ); if (flavor === 'github') { - return ; + return ; } - return ; + return ; }; export default EnrichedMarkdownText;