From b244e56151e38de173098f6e05b61f3cc73bff18 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=9D=B0?= Date: Tue, 10 Oct 2023 10:30:04 +0800 Subject: [PATCH 1/2] =?UTF-8?q?perf:=20=E5=AF=B9=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=BA=93=E7=BB=84=E4=BB=B6=E8=BF=9B=E8=A1=8C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 5 +- packages/react-native/src/accordion/index.tsx | 17 +- .../src/accordion/useAccordion.ts | 9 +- .../react-native/src/action-sheet/index.tsx | 10 +- .../src/avatar/Accessory/index.tsx | 87 ++++----- .../react-native/src/avatar/Avatar/index.tsx | 39 ++-- packages/react-native/src/avatar/type.ts | 4 +- packages/react-native/src/badge/index.tsx | 78 +++++++- packages/react-native/src/badge/useBadge.ts | 29 +++ packages/react-native/src/badge/useBadge.tsx | 83 --------- .../react-native/src/button-group/Item.tsx | 12 +- packages/react-native/src/button/index.tsx | 8 +- packages/react-native/src/button/useButton.ts | 6 +- packages/react-native/src/card/index.tsx | 63 ++++--- .../react-native/src/carousel/Bullets.tsx | 38 ++-- .../react-native/src/carousel/useCarousel.ts | 14 +- .../src/checkbox/CheckboxItem.tsx | 15 +- .../react-native/src/collapse-text/index.tsx | 21 +-- .../react-native/src/count-down/index.tsx | 2 +- packages/react-native/src/empty/index.tsx | 14 +- .../react-native/src/float-button/Actions.tsx | 4 +- packages/react-native/src/flow/index.tsx | 6 +- packages/react-native/src/flow/step.tsx | 16 +- packages/react-native/src/form/FormItem.tsx | 11 +- .../react-native/src/form/FormListItem.tsx | 11 +- .../react-native/src/image-header/index.tsx | 8 +- packages/react-native/src/input/InputItem.tsx | 32 +++- packages/react-native/src/input/TextArea.tsx | 27 ++- packages/react-native/src/input/index.tsx | 70 +++++--- packages/react-native/src/input/useInput.ts | 43 +++++ packages/react-native/src/input/useInput.tsx | 77 -------- .../react-native/src/input/useInputItem.ts | 43 +++++ .../react-native/src/input/useInputItem.tsx | 76 -------- .../react-native/src/input/useTextArea.ts | 23 +++ .../react-native/src/input/useTextArea.tsx | 53 ------ packages/react-native/src/list-item/index.tsx | 96 ++++++---- packages/react-native/src/list/index.tsx | 82 ++++----- packages/react-native/src/menu/Chevron.tsx | 4 +- packages/react-native/src/menu/MenuGroup.tsx | 4 +- packages/react-native/src/menu/useGroup.ts | 2 +- .../src/notice-bar/AnimatedNotice.tsx | 4 +- .../react-native/src/notice-bar/index.tsx | 40 +++-- .../react-native/src/notify/NotifyRoot.tsx | 167 ++++++++++-------- .../react-native/src/pagination/index.tsx | 43 ++--- .../src/pagination/usePagination.ts | 23 ++- packages/react-native/src/pressable/index.tsx | 57 +++--- packages/react-native/src/radio/RadioItem.tsx | 10 +- packages/react-native/src/result/index.tsx | 32 ++-- .../react-native/src/scroll-number/index.tsx | 23 ++- .../react-native/src/search-bar/index.tsx | 8 +- packages/react-native/src/slider/index.tsx | 24 ++- .../src/svg-icon/IconArrowdown.tsx | 9 +- .../react-native/src/svg-icon/IconBells.tsx | 9 +- .../react-native/src/svg-icon/IconCheck.tsx | 9 +- .../src/svg-icon/IconCheckboxChecked.tsx | 9 +- .../src/svg-icon/IconCheckboxHalfchecked.tsx | 9 +- .../src/svg-icon/IconCheckboxUnchecked.tsx | 9 +- .../src/svg-icon/IconCheckcircle.tsx | 9 +- .../src/svg-icon/IconCheckcircleo.tsx | 9 +- .../src/svg-icon/IconClockcircleo.tsx | 9 +- .../react-native/src/svg-icon/IconClose.tsx | 9 +- .../src/svg-icon/IconClosecircleo.tsx | 9 +- .../react-native/src/svg-icon/IconDate.tsx | 9 +- .../react-native/src/svg-icon/IconDown.tsx | 9 +- .../src/svg-icon/IconEllipsis.tsx | 9 +- .../src/svg-icon/IconEyeclose.tsx | 9 +- .../react-native/src/svg-icon/IconEyeopen.tsx | 9 +- .../react-native/src/svg-icon/IconLeft.tsx | 9 +- .../react-native/src/svg-icon/IconMinus.tsx | 9 +- .../react-native/src/svg-icon/IconPlus.tsx | 9 +- .../src/svg-icon/IconRadioChecked.tsx | 9 +- .../src/svg-icon/IconRadioUnchecked.tsx | 9 +- .../react-native/src/svg-icon/IconReload.tsx | 9 +- .../react-native/src/svg-icon/IconRight.tsx | 9 +- .../react-native/src/svg-icon/IconSearch.tsx | 9 +- packages/react-native/src/svg-icon/IconUp.tsx | 9 +- .../react-native/src/swipe-row/context.tsx | 20 ++- packages/react-native/src/swipe-row/index.tsx | 2 +- .../react-native/src/swipe-row/useSwipeRow.ts | 6 +- packages/react-native/src/switch/index.tsx | 10 +- packages/react-native/src/table/Cell.tsx | 6 +- packages/react-native/src/table/Head.tsx | 6 +- packages/react-native/src/table/Rows.tsx | 6 +- packages/react-native/src/table/index.tsx | 4 +- packages/react-native/src/tag/index.tsx | 85 ++++----- packages/react-native/src/text/index.tsx | 7 +- .../src/timeline/HorizontalTimeline.tsx | 123 +++++++------ .../src/timeline/VerticalTimeline.tsx | 140 ++++++++------- .../react-native/src/tooltip/Triangle.tsx | 6 +- packages/react-native/src/tooltip/index.tsx | 86 ++++++--- packages/react-native/src/tree/Checkbox.tsx | 8 +- packages/react-native/src/tree/Chevron.tsx | 4 +- packages/react-native/src/tree/TreeGroup.tsx | 6 +- packages/react-native/src/tree/useGroup.ts | 2 +- .../react-native/src/white-space/index.tsx | 4 +- .../react-native/src/wing-blank/index.tsx | 4 +- pnpm-lock.yaml | 103 +++++------ 97 files changed, 1260 insertions(+), 1276 deletions(-) create mode 100644 packages/react-native/src/badge/useBadge.ts delete mode 100644 packages/react-native/src/badge/useBadge.tsx create mode 100644 packages/react-native/src/input/useInput.ts delete mode 100644 packages/react-native/src/input/useInput.tsx create mode 100644 packages/react-native/src/input/useInputItem.ts delete mode 100644 packages/react-native/src/input/useInputItem.tsx create mode 100644 packages/react-native/src/input/useTextArea.ts delete mode 100644 packages/react-native/src/input/useTextArea.tsx diff --git a/package.json b/package.json index c06a538e94..b6eaceda85 100644 --- a/package.json +++ b/package.json @@ -59,5 +59,8 @@ "engines": { "node": ">=16", "pnpm": ">=7.0.0" + }, + "resolutions": { + "@types/react": "17.0.43" } -} +} \ No newline at end of file diff --git a/packages/react-native/src/accordion/index.tsx b/packages/react-native/src/accordion/index.tsx index 3333a625e2..91d8cc3faf 100644 --- a/packages/react-native/src/accordion/index.tsx +++ b/packages/react-native/src/accordion/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useState } from 'react'; +import React, { FC, useMemo, useState } from 'react'; import { FlatList } from 'react-native'; import Animated from 'react-native-reanimated'; @@ -82,7 +82,7 @@ const AccordionItem: FC< onPress, }); - const renderTitle = () => { + const Title = useMemo(() => { if (typeof title === 'string') { return ( @@ -91,17 +91,18 @@ const AccordionItem: FC< ); } return title; - }; + }, [title]); - const renderContent = () => { - if (typeof content === 'string') + const Content = useMemo(() => { + if (typeof content === 'string') { return ( {content} ); + } return content; - }; + }, [content]); return ( @@ -122,7 +123,7 @@ const AccordionItem: FC< headerStyle, ]} > - {renderTitle()} + {Title} {customIcon ? ( customIcon({ progress }) ) : ( @@ -133,7 +134,7 @@ const AccordionItem: FC< - {renderContent()} + {Content} diff --git a/packages/react-native/src/accordion/useAccordion.ts b/packages/react-native/src/accordion/useAccordion.ts index 08dfc06f19..b55916d219 100644 --- a/packages/react-native/src/accordion/useAccordion.ts +++ b/packages/react-native/src/accordion/useAccordion.ts @@ -52,13 +52,8 @@ export default function useAccordion({ }, [multiple, currentIndex, index, onPress]); const handlePress = () => { + progress.value = withTiming(progress.value === 0 ? 1 : 0); onPress(index); - - if (progress.value === 0) { - progress.value = withTiming(1); - } else { - progress.value = withTiming(0); - } }; return { @@ -66,7 +61,7 @@ export default function useAccordion({ iconStyle, progress, - handleLayout: useMemoizedFn(handleLayout), + handleLayout, handlePress: useMemoizedFn(handlePress), }; } diff --git a/packages/react-native/src/action-sheet/index.tsx b/packages/react-native/src/action-sheet/index.tsx index a955e75fad..f50c3a3f86 100644 --- a/packages/react-native/src/action-sheet/index.tsx +++ b/packages/react-native/src/action-sheet/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, ReactNode } from 'react'; +import React, { FC, ReactNode, useMemo } from 'react'; import { StyleSheet } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -52,8 +52,9 @@ const ActionSheet: FC = ({ }, }); - const renderTitle = () => { + const Title = useMemo(() => { if (!title) return null; + if (typeof title === 'string') return ( @@ -62,8 +63,9 @@ const ActionSheet: FC = ({ ); + return {title}; - }; + }, [title]); return ( = ({ maskClosable={false} maskVisible={true} > - {renderTitle()} + {Title} {items.map((item, index) => ( { - /** 挂件的reader */ - const iconReader = () => { - if (url) { - const source = typeof url === 'string' ? { uri: url } : url; - return ( - - ); - } - if (component) { - return component; - } - return null; - }; - /** 挂件的位置 */ - const styles = StyleSheet.create({ - position: { - borderRadius: size / 2, - }, - top: { - top: 0, - }, - bottom: { - bottom: 0, - }, - left: { - left: 0, - }, - right: { - right: 0, - }, - }); - return ( - {iconReader()} + ); }; Accessory.displayName = 'Accessory'; +/** 挂件的位置 */ +const styles = StyleSheet.create({ + top: { + top: 0, + }, + bottom: { + bottom: 0, + }, + left: { + left: 0, + }, + right: { + right: 0, + }, +}); + export default Accessory; + +const Icon = memo(({ url, size, component }: Pick) => { + if (url) { + const source = typeof url === 'string' ? { uri: url } : url; + return ( + + ); + } + if (component) { + return component; + } + return null; +}); diff --git a/packages/react-native/src/avatar/Avatar/index.tsx b/packages/react-native/src/avatar/Avatar/index.tsx index 96ab9d5d29..54bd074881 100644 --- a/packages/react-native/src/avatar/Avatar/index.tsx +++ b/packages/react-native/src/avatar/Avatar/index.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { Image, StyleSheet } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -27,7 +27,29 @@ const Avatar: FC = ({ title, url, textStyle, ...props }) => { }, }); - const renderImage = () => { + return ( + + + + ); +}; +Avatar.displayName = 'Avatar'; + +export default Avatar; + +const Content = memo( + ({ + url, + title, + width, + height, + avatarRadius, + textStyle, + }: Pick & { + width: number; + height: number; + avatarRadius: number; + }) => { if (!!url) return ( = ({ title, url, textStyle, ...props }) => { ); return null; - }; - - return ( - - {renderImage()} - - ); -}; -Avatar.displayName = 'Avatar'; - -export default Avatar; + } +); diff --git a/packages/react-native/src/avatar/type.ts b/packages/react-native/src/avatar/type.ts index 69443a20b8..6c6b9deb46 100644 --- a/packages/react-native/src/avatar/type.ts +++ b/packages/react-native/src/avatar/type.ts @@ -1,4 +1,4 @@ -import { PropsWithChildren, ReactNode } from 'react'; +import { PropsWithChildren, ReactElement } from 'react'; import { TextStyle, ViewStyle } from 'react-native'; export interface AccessoryProps { @@ -7,7 +7,7 @@ export interface AccessoryProps { /** 使用图片时的值 */ url?: string | number; /** 使用自定义组件 */ - component?: ReactNode; + component?: ReactElement; /** 挂件垂直方向位置 */ top?: boolean; /** 挂件水平方向位置 */ diff --git a/packages/react-native/src/badge/index.tsx b/packages/react-native/src/badge/index.tsx index 7c2999ee88..552cbc686f 100644 --- a/packages/react-native/src/badge/index.tsx +++ b/packages/react-native/src/badge/index.tsx @@ -1,9 +1,11 @@ -import React, { cloneElement, FC, ReactElement } from 'react'; -import { TextStyle, ViewStyle } from 'react-native'; +import React, { cloneElement, FC, memo, ReactElement } from 'react'; +import { StyleSheet, TextStyle, ViewStyle } from 'react-native'; import Box from '../box'; +import Text from '../text'; import useBadge from './useBadge'; +const DOT_SIZE = 8; // 默认点大小 export interface BadgeProps { /** 徽标内容 */ text?: string | number; @@ -19,18 +21,80 @@ export interface BadgeProps { children: ReactElement; } -const Badge: FC = props => { - const { renderContent, onBadgeLayout, width, height } = useBadge(props); +const Badge: FC = ({ + type = 'text', + containerStyle = {}, + textStyle = {}, + text, + max = 99, + children, +}: BadgeProps) => { + const { onBadgeLayout, badgeOffset, layout } = useBadge(); return ( - - {cloneElement(props.children, { + + {cloneElement(children, { onLayout: onBadgeLayout, })} - {renderContent()} + ); }; Badge.displayName = 'Badge'; export default Badge; + +const Content = memo( + ({ + type, + text, + max, + containerStyle, + textStyle, + badgeOffset, + }: Pick & { + badgeOffset: { top: number; right: number }; + }) => { + text = typeof text === 'number' && text > max! ? `${max}+` : text; + + const isZero = text === '0' || text === 0; + const isEmpty = text === null || text === undefined || text === ''; + const isHidden = isEmpty || isZero; + + if (isHidden) return null; + + if (type === 'dot') + return ( + + ); + return ( + + + {text} + + + ); + } +); diff --git a/packages/react-native/src/badge/useBadge.ts b/packages/react-native/src/badge/useBadge.ts new file mode 100644 index 0000000000..657e2dbb5f --- /dev/null +++ b/packages/react-native/src/badge/useBadge.ts @@ -0,0 +1,29 @@ +import { LayoutChangeEvent } from 'react-native'; + +import { useSafeState } from '@td-design/rn-hooks'; + +export default function useBadge() { + const [layout, setLayout] = useSafeState({ width: 0, height: 0 }); + const [badgeOffset, setBadgeOffset] = useSafeState({ + top: 0, + right: 0, + }); + + const onBadgeLayout = (event: LayoutChangeEvent) => { + const { width, height } = event.nativeEvent.layout; + const newX = Math.round(-width / 2); + const newY = Math.round(-height / 2); + + setLayout({ width, height }); + + if (badgeOffset.top !== newY || badgeOffset.right !== newX) { + setBadgeOffset({ top: newY, right: newX }); + } + }; + + return { + badgeOffset, + layout, + onBadgeLayout, + }; +} diff --git a/packages/react-native/src/badge/useBadge.tsx b/packages/react-native/src/badge/useBadge.tsx deleted file mode 100644 index e4b1ff9bab..0000000000 --- a/packages/react-native/src/badge/useBadge.tsx +++ /dev/null @@ -1,83 +0,0 @@ -import React, { useCallback, useState } from 'react'; -import { LayoutChangeEvent, StyleSheet } from 'react-native'; - -import { useSafeState } from '@td-design/rn-hooks'; - -import type { BadgeProps } from '.'; -import Box from '../box'; -import Text from '../text'; - -const DOT_SIZE = 8; // 默认点大小 -export default function useBadge({ type = 'text', containerStyle = {}, textStyle = {}, text, max = 99 }: BadgeProps) { - text = typeof text === 'number' && text > max ? `${max}+` : text; - - const isZero = text === '0' || text === 0; - const isEmpty = text === null || text === undefined || text === ''; - const isHidden = isEmpty || isZero; - - const [layout, setLayout] = useState({ width: 0, height: 0 }); - const [badgeOffset, setBadgeOffset] = useSafeState<{ top: number; right: number }>({ - top: 0, - right: 0, - }); - - const onBadgeLayout = useCallback( - (event: LayoutChangeEvent) => { - const { width, height } = event.nativeEvent.layout; - const newX = Math.round(-width / 2); - const newY = Math.round(-height / 2); - - setLayout({ width, height }); - - if (badgeOffset.top !== newY || badgeOffset.right !== newX) { - setBadgeOffset({ top: newY, right: newX }); - } - }, - [badgeOffset] - ); - - const renderContent = () => { - if (isHidden) return null; - - if (type === 'dot') - return ( - - ); - return ( - - - {text} - - - ); - }; - - return { - renderContent, - onBadgeLayout, - width: layout.width, - height: layout.height, - }; -} diff --git a/packages/react-native/src/button-group/Item.tsx b/packages/react-native/src/button-group/Item.tsx index 4932e445e7..7e2efe51a9 100644 --- a/packages/react-native/src/button-group/Item.tsx +++ b/packages/react-native/src/button-group/Item.tsx @@ -1,4 +1,4 @@ -import React, { cloneElement, FC, memo, ReactElement, ReactNode } from 'react'; +import React, { cloneElement, FC, memo, ReactElement, ReactNode, useMemo } from 'react'; import { StyleProp, StyleSheet, ViewStyle } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -72,7 +72,7 @@ const ButtonItem: FC = ({ }, }); - const renderLabel = () => { + const Label = useMemo(() => { const textColor = isCurrent ? theme.colors.text_active : theme.colors.primary200; if (typeof label === 'string') @@ -81,7 +81,7 @@ const ButtonItem: FC = ({ variant={'p1'} textAlign={'center'} style={{ - color: disabled ? theme.colors.disabled : textColor, + color: disabled ? theme.colors.gray200 : textColor, }} > {label} @@ -92,7 +92,7 @@ const ButtonItem: FC = ({ color: textColor, }, }); - }; + }, [label, isCurrent, disabled, theme.colors.primary200, theme.colors.text_active, theme.colors.gray200]); if (!disabled) return ( @@ -104,13 +104,13 @@ const ButtonItem: FC = ({ }} style={StyleSheet.flatten([styles.item, isFirst && styles.first, isLast && styles.last, itemStyle])} > - {renderLabel()} + {Label} ); return ( - {renderLabel()} + {Label} ); }; diff --git a/packages/react-native/src/button/index.tsx b/packages/react-native/src/button/index.tsx index f553f25d23..b1dbe3399d 100644 --- a/packages/react-native/src/button/index.tsx +++ b/packages/react-native/src/button/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, ReactNode } from 'react'; +import React, { FC, ReactNode, useMemo } from 'react'; import { DimensionValue } from 'react-native'; import helpers from '../helpers'; @@ -34,7 +34,7 @@ const Button: FC = props => { const { pressableProps, textColor, variant, indicatorColor } = useButton(props); - const renderText = () => { + const Title = useMemo(() => { if (typeof title === 'string') return ( @@ -42,14 +42,14 @@ const Button: FC = props => { ); return title; - }; + }, [title, textColor, variant]); return ( {!!loading && ( )} - {renderText()} + {Title} ); }; diff --git a/packages/react-native/src/button/useButton.ts b/packages/react-native/src/button/useButton.ts index 527103e8ed..c089337cd9 100644 --- a/packages/react-native/src/button/useButton.ts +++ b/packages/react-native/src/button/useButton.ts @@ -26,14 +26,14 @@ export default function useButton(props: ButtonProps) { let textColor: Color = 'text_active'; let backgroundColor = theme.colors.transparent; - let indicatorColor = disabled ? theme.colors.gray400 : theme.colors.white; + let indicatorColor = disabled ? theme.colors.gray200 : theme.colors.white; if (type === 'primary') { backgroundColor = disabled ? theme.colors.primary400 : theme.colors.primary200; } else if (type === 'secondary') { - textColor = disabled ? 'disabled' : 'primary200'; + textColor = disabled ? 'gray200' : 'primary200'; backgroundColor = disabled ? theme.colors.disabled : theme.colors.transparent; - indicatorColor = disabled ? theme.colors.gray400 : theme.colors.primary200; + indicatorColor = disabled ? theme.colors.gray200 : theme.colors.primary200; } let borderWidth = 0; diff --git a/packages/react-native/src/card/index.tsx b/packages/react-native/src/card/index.tsx index d02fc72364..0994268168 100644 --- a/packages/react-native/src/card/index.tsx +++ b/packages/react-native/src/card/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, PropsWithChildren, ReactNode } from 'react'; +import React, { FC, memo, PropsWithChildren, ReactNode } from 'react'; import { StyleProp, StyleSheet, ViewStyle } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -45,9 +45,32 @@ const Card: FC> = ({ contentStyle, children, }) => { - const theme = useTheme(); + return ( + +
+ {children} + {!!footer && {footer}} + + ); +}; +Card.displayName = 'Card'; - const _renderHeader = () => { +export default Card; + +const Header = memo( + ({ + hideHeader, + icon, + title, + extra, + renderHeader, + }: Pick) => { if (hideHeader) return null; const Header = ( @@ -93,9 +116,13 @@ const Card: FC> = ({ {renderHeader ? renderHeader() : Header} ); - }; + } +); + +const Body = memo( + ({ footer, contentStyle, children }: Pick, 'footer' | 'contentStyle' | 'children'>) => { + const theme = useTheme(); - const _renderBody = () => { return ( > = ({ {children} ); - }; - - const _renderFooter = () => { - if (!!footer) return {footer}; - return null; - }; - - return ( - - {_renderHeader()} - {_renderBody()} - {_renderFooter()} - - ); -}; -Card.displayName = 'Card'; - -export default Card; + } +); diff --git a/packages/react-native/src/carousel/Bullets.tsx b/packages/react-native/src/carousel/Bullets.tsx index d955d316a6..7e53b52021 100644 --- a/packages/react-native/src/carousel/Bullets.tsx +++ b/packages/react-native/src/carousel/Bullets.tsx @@ -58,25 +58,27 @@ const Bullets = ({ }; Bullets.displayName = 'Bullets'; -const Dot = (props: { isCurrent: boolean; activeColor?: string; inactiveColor?: string; indicatorSize: number }) => { - const theme = useTheme(); - const { isCurrent, activeColor = theme.colors.gray50, inactiveColor = theme.colors.gray200, indicatorSize } = props; +export default memo(Bullets); - const backgroundColor = mixColor(+isCurrent, inactiveColor, activeColor) as any; - const scale = mix(+isCurrent, 1, 1.2); +const Dot = memo( + (props: { isCurrent: boolean; activeColor?: string; inactiveColor?: string; indicatorSize: number }) => { + const theme = useTheme(); + const { isCurrent, activeColor = theme.colors.gray50, inactiveColor = theme.colors.gray200, indicatorSize } = props; - const styles = StyleSheet.create({ - dot: { - width: indicatorSize, - height: indicatorSize, - borderRadius: indicatorSize / 2, - backgroundColor, - transform: [{ scale }], - marginHorizontal: indicatorSize / 2, - }, - }); + const backgroundColor = mixColor(+isCurrent, inactiveColor, activeColor) as any; + const scale = mix(+isCurrent, 1, 1.2); - return ; -}; + const styles = StyleSheet.create({ + dot: { + width: indicatorSize, + height: indicatorSize, + borderRadius: indicatorSize / 2, + backgroundColor, + transform: [{ scale }], + marginHorizontal: indicatorSize / 2, + }, + }); -export default memo(Bullets); + return ; + } +); diff --git a/packages/react-native/src/carousel/useCarousel.ts b/packages/react-native/src/carousel/useCarousel.ts index fd1834a46f..8d3843af54 100644 --- a/packages/react-native/src/carousel/useCarousel.ts +++ b/packages/react-native/src/carousel/useCarousel.ts @@ -21,6 +21,12 @@ export default function useCarousel({ setCurrentIndex(index => (index === count - 1 ? 0 : index + 1)); }); + // 用户手动滚动开始时,停止轮播 + const clearTimer = useMemoizedFn(() => { + clearInterval(timer.current); + timer.current = undefined; + }); + useEffect(() => { if (!auto) return; @@ -37,12 +43,6 @@ export default function useCarousel({ timer.current = setInterval(loop, duration); }; - // 用户手动滚动开始时,停止轮播 - const clearTimer = () => { - clearInterval(timer.current); - timer.current = undefined; - }; - // 在ScrollView滚动结束后,修改当前index const onScrollEnd = (e: NativeSyntheticEvent) => { const { x } = e.nativeEvent.contentOffset; @@ -64,7 +64,7 @@ export default function useCarousel({ scrollViewRef, currentIndex, - onTouchStart: useMemoizedFn(clearTimer), + onTouchStart: clearTimer, onTouchEnd: useMemoizedFn(onTouchEnd), onScrollEnd: useMemoizedFn(onScrollEnd), }; diff --git a/packages/react-native/src/checkbox/CheckboxItem.tsx b/packages/react-native/src/checkbox/CheckboxItem.tsx index 655186c788..f4f1eab041 100644 --- a/packages/react-native/src/checkbox/CheckboxItem.tsx +++ b/packages/react-native/src/checkbox/CheckboxItem.tsx @@ -1,7 +1,8 @@ -import React, { FC, memo } from 'react'; +import React, { FC, memo, useMemo } from 'react'; import { Keyboard, StyleSheet } from 'react-native'; import { useTheme } from '@shopify/restyle'; +import { useMemoizedFn } from '@td-design/rn-hooks'; import Box from '../box'; import Flex from '../flex'; @@ -38,13 +39,13 @@ const CheckboxItem: FC = ({ }, }); - const handleChange = () => { + const handleChange = useMemoizedFn(() => { Keyboard.dismiss(); if (disabled) return; onChange?.(value, status); - }; + }); - const renderLabel = () => { + const Label = useMemo(() => { if (typeof label === 'string') return ( @@ -52,7 +53,7 @@ const CheckboxItem: FC = ({ ); return label; - }; + }, [disabled, label, labelStyle]); if (!disabled) return ( @@ -65,7 +66,7 @@ const CheckboxItem: FC = ({ - {renderLabel()} + {Label} ); @@ -76,7 +77,7 @@ const CheckboxItem: FC = ({ - {renderLabel()} + {Label} ); diff --git a/packages/react-native/src/collapse-text/index.tsx b/packages/react-native/src/collapse-text/index.tsx index aaf98fb182..e08db07d74 100644 --- a/packages/react-native/src/collapse-text/index.tsx +++ b/packages/react-native/src/collapse-text/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useCallback } from 'react'; +import React, { FC } from 'react'; import { LayoutChangeEvent, StyleProp, StyleSheet, TextStyle, ViewStyle } from 'react-native'; import { useBoolean } from '@td-design/rn-hooks'; @@ -45,17 +45,14 @@ const CollapseText: FC = ({ const [isOverflow, { set: setOverflow }] = useBoolean(false); const [hidden, { toggle: toggleHidden }] = useBoolean(true); - const handleLayout = useCallback( - (e: LayoutChangeEvent) => { - const { height } = e.nativeEvent.layout; - if (height - 1 < lineHeight * defaultNumberOfLines) { - setOverflow(false); - } else { - setOverflow(true); - } - }, - [lineHeight, defaultNumberOfLines] - ); + const handleLayout = (e: LayoutChangeEvent) => { + const { height } = e.nativeEvent.layout; + if (height - 1 < lineHeight * defaultNumberOfLines) { + setOverflow(false); + } else { + setOverflow(true); + } + }; const styles = StyleSheet.create({ container: { diff --git a/packages/react-native/src/count-down/index.tsx b/packages/react-native/src/count-down/index.tsx index d61a6ed42a..eb2166aff6 100644 --- a/packages/react-native/src/count-down/index.tsx +++ b/packages/react-native/src/count-down/index.tsx @@ -104,7 +104,7 @@ const CountDown = forwardRef( activeOpacity={activeOpacity} onPress={handlePress} > - + {text} diff --git a/packages/react-native/src/empty/index.tsx b/packages/react-native/src/empty/index.tsx index cdb26f6aca..8e0e92766a 100644 --- a/packages/react-native/src/empty/index.tsx +++ b/packages/react-native/src/empty/index.tsx @@ -1,4 +1,4 @@ -import React, { ReactNode } from 'react'; +import React, { ReactNode, useMemo } from 'react'; import Svg, { Ellipse, G, Path } from 'react-native-svg'; import { BoxProps } from '@shopify/restyle'; @@ -15,7 +15,7 @@ type EmptyProps = BoxProps & { }; const Empty: React.FC = ({ emptyText = '暂无数据', customImg, ...boxProps }) => { - const renderTextDom = () => { + const EmptyText = useMemo(() => { if (typeof emptyText === 'string') { return ( @@ -24,9 +24,9 @@ const Empty: React.FC = ({ emptyText = '暂无数据', customImg, .. ); } return emptyText; - }; + }, [emptyText]); - const renderImgDom = () => { + const EmptyImage = useMemo(() => { if (customImg) return customImg; return ( @@ -43,12 +43,12 @@ const Empty: React.FC = ({ emptyText = '暂无数据', customImg, .. ); - }; + }, [customImg]); return ( - {renderImgDom()} - {renderTextDom()} + {EmptyImage} + {EmptyText} ); }; diff --git a/packages/react-native/src/float-button/Actions.tsx b/packages/react-native/src/float-button/Actions.tsx index efee327c5e..f1ff2bc15a 100644 --- a/packages/react-native/src/float-button/Actions.tsx +++ b/packages/react-native/src/float-button/Actions.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { StyleSheet } from 'react-native'; import Box from '../box'; @@ -33,4 +33,4 @@ const Actions: FC = props => { }; Actions.displayName = 'Actions'; -export default Actions; +export default memo(Actions); diff --git a/packages/react-native/src/flow/index.tsx b/packages/react-native/src/flow/index.tsx index 328c5b4c97..f27fd1b744 100644 --- a/packages/react-native/src/flow/index.tsx +++ b/packages/react-native/src/flow/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, useCallback } from 'react'; +import React, { FC } from 'react'; import { LayoutChangeEvent } from 'react-native'; import { useSafeState } from '@td-design/rn-hooks'; @@ -33,9 +33,9 @@ const Flow: FC = ({ steps = [], size = px(36), current = 0, status = /** 单条线的长度 */ const tailWidth = (wrapWidth - iconWidth) / (steps.length - 1); - const handleLayout = useCallback((e: LayoutChangeEvent) => { + const handleLayout = (e: LayoutChangeEvent) => { setWrapWidth(e.nativeEvent.layout.width); - }, []); + }; return ( diff --git a/packages/react-native/src/flow/step.tsx b/packages/react-native/src/flow/step.tsx index 3874182687..901880d39f 100644 --- a/packages/react-native/src/flow/step.tsx +++ b/packages/react-native/src/flow/step.tsx @@ -1,4 +1,4 @@ -import React, { cloneElement, FC, isValidElement, memo, ReactElement } from 'react'; +import React, { cloneElement, FC, isValidElement, memo, ReactElement, useMemo } from 'react'; import { useTheme } from '@shopify/restyle'; @@ -72,7 +72,7 @@ const Step: FC = ({ * 3 更具当前的状态进行选择使用的icon * 4 可以使用label */ - const iconRender = () => { + const IconRender = useMemo(() => { if (!!stepRender && isValidElement(stepRender)) { return cloneElement(stepRender as ReactElement, {}); } @@ -91,12 +91,12 @@ const Step: FC = ({ ); } return ; - }; + }, [icon, iconSize, label, stepRender, status, theme.colors.white]); /** * 尾巴的样式 */ - const tailRender = () => { + const TailRender = useMemo(() => { if (isLast) return null; if (!active || isCurrent) return ( @@ -113,14 +113,14 @@ const Step: FC = ({ }} /> ); - }; + }, [active, iconActiveColor, isCurrent, isLast, size]); return ( {stepRender ? ( - iconRender() + IconRender ) : ( = ({ borderRadius: size / 2, }} > - {iconRender()} + {IconRender} )} @@ -151,7 +151,7 @@ const Step: FC = ({ )} - {tailRender()} + {TailRender} ); }; diff --git a/packages/react-native/src/form/FormItem.tsx b/packages/react-native/src/form/FormItem.tsx index 1a80850e84..58121d945b 100644 --- a/packages/react-native/src/form/FormItem.tsx +++ b/packages/react-native/src/form/FormItem.tsx @@ -1,4 +1,4 @@ -import React, { FC, useContext, useRef } from 'react'; +import React, { FC, useContext, useMemo, useRef } from 'react'; import { useTheme } from '@shopify/restyle'; import { useSafeState } from '@td-design/rn-hooks'; @@ -37,12 +37,15 @@ const FormItem: FC = ({ children, type = 'bottom', name, ...field return {}; }; - const Error = - errors.length > 0 ? ( + const Error = useMemo(() => { + if (errors.length === 0) return null; + + return ( {errors[0]} - ) : null; + ); + }, [errors]); return ( diff --git a/packages/react-native/src/form/FormListItem.tsx b/packages/react-native/src/form/FormListItem.tsx index 90dd68dc63..ee9b8cba4d 100644 --- a/packages/react-native/src/form/FormListItem.tsx +++ b/packages/react-native/src/form/FormListItem.tsx @@ -1,4 +1,4 @@ -import React, { FC, useContext, useRef } from 'react'; +import React, { FC, useContext, useMemo, useRef } from 'react'; import { useTheme } from '@shopify/restyle'; import { useSafeState } from '@td-design/rn-hooks'; @@ -39,12 +39,15 @@ const FormListItem: FC = ({ } }; - const Error = - errors.length > 0 ? ( + const Error = useMemo(() => { + if (errors.length === 0) return null; + + return ( {errors[0]} - ) : null; + ); + }, [errors]); return ( = props => { }, }); - const renderHeaderLeft = () => { + const HeaderLeft = useMemo(() => { if (headerLeft) { if (typeof headerLeft === 'string') { return ( @@ -77,14 +77,14 @@ const ImageHeader: FC = props => { return headerLeft; } return ; - }; + }, [headerLeft, headerLeftColor]); return ( {showLeft ? ( - {renderHeaderLeft()} + {HeaderLeft} ) : ( diff --git a/packages/react-native/src/input/InputItem.tsx b/packages/react-native/src/input/InputItem.tsx index 8d7f5fb363..053e8aeb44 100644 --- a/packages/react-native/src/input/InputItem.tsx +++ b/packages/react-native/src/input/InputItem.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, ReactNode } from 'react'; +import React, { forwardRef, memo, ReactNode } from 'react'; import { StyleProp, StyleSheet, TextInput, TextInputProps, TextStyle, ViewStyle } from 'react-native'; import Animated, { FadeInRight, FadeOutRight } from 'react-native-reanimated'; @@ -67,15 +67,12 @@ const InputItem = forwardRef( ref ) => { const theme = useTheme(); - const { LabelComp, inputValue, eyeOpen, handleChange, handleInputClear, triggerPasswordType } = useInputItem({ + const { inputValue, eyeOpen, handleChange, handleInputClear, triggerPasswordType } = useInputItem({ inputType, - label, value, defaultValue, onChange, onClear, - colon, - required, }); const styles = StyleSheet.create({ @@ -140,7 +137,7 @@ const InputItem = forwardRef( return ( - {LabelComp} + ); - const Brief = brief ? ( - - {typeof brief === 'string' ? ( - - {brief} - - ) : ( - brief - )} - - ) : null; - return labelPosition === 'left' ? ( - {LabelComp} + ) : ( - {LabelComp} + ); } @@ -182,3 +166,41 @@ export default Object.assign(Input, { InputItem, TextArea, }); + +const Label = memo(({ colon, label, required }: Pick) => { + if (!label) return null; + + if (typeof label === 'string') + return ( + + {required && *} + + + {colon ? ':' : ''} + + ); + + return ( + + {required && *} + + ); +}); + +const Brief = memo(({ brief }: Pick) => { + if (!brief) return null; + return ( + + {typeof brief === 'string' ? ( + + {brief} + + ) : ( + brief + )} + + ); +}); diff --git a/packages/react-native/src/input/useInput.ts b/packages/react-native/src/input/useInput.ts new file mode 100644 index 0000000000..95395afb14 --- /dev/null +++ b/packages/react-native/src/input/useInput.ts @@ -0,0 +1,43 @@ +import { useEffect } from 'react'; + +import { useMemoizedFn, useSafeState } from '@td-design/rn-hooks'; + +import type { InputProps } from '.'; + +export default function useInput({ + inputType, + value, + defaultValue, + onChange, + onClear, +}: Pick) { + const [inputValue, setInputValue] = useSafeState(); + const [eyeOpen, setEyeOpen] = useSafeState(inputType === 'password'); + + useEffect(() => { + setInputValue(value || defaultValue); + }, [value, defaultValue]); + + const handleInputClear = () => { + setInputValue(''); + onChange?.(''); + onClear?.(); + }; + + const handleChange = (val: string) => { + setInputValue(val); + onChange?.(val); + }; + + const triggerPasswordType = () => { + setEyeOpen(!eyeOpen); + }; + + return { + inputValue, + eyeOpen, + handleChange: useMemoizedFn(handleChange), + handleInputClear: useMemoizedFn(handleInputClear), + triggerPasswordType: useMemoizedFn(triggerPasswordType), + }; +} diff --git a/packages/react-native/src/input/useInput.tsx b/packages/react-native/src/input/useInput.tsx deleted file mode 100644 index 1bbc0d58f3..0000000000 --- a/packages/react-native/src/input/useInput.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React, { useEffect, useMemo } from 'react'; - -import { useMemoizedFn, useSafeState } from '@td-design/rn-hooks'; - -import type { InputProps } from '.'; -import Flex from '../flex'; -import Text from '../text'; - -export default function useInput({ - inputType, - labelPosition, - label, - value, - defaultValue, - onChange, - onClear, - colon = false, - required = false, -}: Pick< - InputProps, - 'inputType' | 'labelPosition' | 'label' | 'value' | 'defaultValue' | 'onChange' | 'onClear' | 'colon' | 'required' ->) { - const [inputValue, setInputValue] = useSafeState(); - const [eyeOpen, setEyeOpen] = useSafeState(inputType === 'password'); - - useEffect(() => { - setInputValue(value || defaultValue); - }, [value, defaultValue]); - - const handleInputClear = () => { - setInputValue(''); - onChange?.(''); - onClear?.(); - }; - - const handleChange = (val: string) => { - setInputValue(val); - onChange?.(val); - }; - - const triggerPasswordType = () => { - setEyeOpen(!eyeOpen); - }; - - const LabelComp = useMemo(() => { - if (label) { - if (typeof label === 'string') { - return ( - - {required && *} - - {label} - - {colon ? ':' : ''} - - ); - } - return ( - - {required && *} - {label} - {colon ? ':' : ''} - - ); - } - return null; - }, [colon, label, labelPosition, required]); - - return { - LabelComp, - inputValue, - eyeOpen, - handleChange: useMemoizedFn(handleChange), - handleInputClear: useMemoizedFn(handleInputClear), - triggerPasswordType: useMemoizedFn(triggerPasswordType), - }; -} diff --git a/packages/react-native/src/input/useInputItem.ts b/packages/react-native/src/input/useInputItem.ts new file mode 100644 index 0000000000..b3dfdf9113 --- /dev/null +++ b/packages/react-native/src/input/useInputItem.ts @@ -0,0 +1,43 @@ +import { useEffect } from 'react'; + +import { useMemoizedFn, useSafeState } from '@td-design/rn-hooks'; + +import type { InputItemProps } from './InputItem'; + +export default function useInputItem({ + inputType, + value, + defaultValue, + onChange, + onClear, +}: Pick) { + const [inputValue, setInputValue] = useSafeState(); + const [eyeOpen, setEyeOpen] = useSafeState(inputType === 'password'); + + useEffect(() => { + setInputValue(value || defaultValue); + }, [value, defaultValue]); + + const handleInputClear = () => { + setInputValue(''); + onChange?.(''); + onClear?.(); + }; + + const handleChange = (val: string) => { + setInputValue(val); + onChange?.(val); + }; + + const triggerPasswordType = () => { + setEyeOpen(!eyeOpen); + }; + + return { + inputValue, + eyeOpen, + handleChange: useMemoizedFn(handleChange), + handleInputClear: useMemoizedFn(handleInputClear), + triggerPasswordType: useMemoizedFn(triggerPasswordType), + }; +} diff --git a/packages/react-native/src/input/useInputItem.tsx b/packages/react-native/src/input/useInputItem.tsx deleted file mode 100644 index 1661879983..0000000000 --- a/packages/react-native/src/input/useInputItem.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import React, { useEffect, useMemo } from 'react'; - -import { useMemoizedFn, useSafeState } from '@td-design/rn-hooks'; - -import Flex from '../flex'; -import Text from '../text'; -import type { InputItemProps } from './InputItem'; - -export default function useInputItem({ - inputType, - label, - value, - defaultValue, - onChange, - onClear, - colon = false, - required = false, -}: Pick< - InputItemProps, - 'inputType' | 'label' | 'value' | 'defaultValue' | 'onChange' | 'onClear' | 'colon' | 'required' ->) { - const [inputValue, setInputValue] = useSafeState(); - const [eyeOpen, setEyeOpen] = useSafeState(inputType === 'password'); - - useEffect(() => { - setInputValue(value || defaultValue); - }, [value, defaultValue]); - - const handleInputClear = () => { - setInputValue(''); - onChange?.(''); - onClear?.(); - }; - - const handleChange = (val: string) => { - setInputValue(val); - onChange?.(val); - }; - - const triggerPasswordType = () => { - setEyeOpen(!eyeOpen); - }; - - const LabelComp = useMemo(() => { - if (label) { - if (typeof label === 'string') { - return ( - - {required && *} - - {label} - - {!!colon && :} - - ); - } - return ( - - {required && *} - {label} - {!!colon && :} - - ); - } - return null; - }, [colon, label, required]); - - return { - LabelComp, - inputValue, - eyeOpen, - handleChange: useMemoizedFn(handleChange), - handleInputClear: useMemoizedFn(handleInputClear), - triggerPasswordType: useMemoizedFn(triggerPasswordType), - }; -} diff --git a/packages/react-native/src/input/useTextArea.ts b/packages/react-native/src/input/useTextArea.ts new file mode 100644 index 0000000000..305664a17b --- /dev/null +++ b/packages/react-native/src/input/useTextArea.ts @@ -0,0 +1,23 @@ +import { useEffect } from 'react'; + +import { useSafeState } from '@td-design/rn-hooks'; + +import type { TextAreaProps } from './TextArea'; + +export default function useTextArea({ value = '', onChange }: Pick) { + const [inputValue, setInputValue] = useSafeState(value); + + useEffect(() => { + setInputValue(value); + }, [value]); + + const handleChange = (val: string) => { + setInputValue(val); + onChange?.(val); + }; + + return { + inputValue, + handleChange, + }; +} diff --git a/packages/react-native/src/input/useTextArea.tsx b/packages/react-native/src/input/useTextArea.tsx deleted file mode 100644 index 7c11660b99..0000000000 --- a/packages/react-native/src/input/useTextArea.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import React, { useEffect, useMemo } from 'react'; - -import { useSafeState } from '@td-design/rn-hooks'; - -import Flex from '../flex'; -import Text from '../text'; -import type { TextAreaProps } from './TextArea'; - -export default function useTextArea({ - value = '', - onChange, - label, - required = false, -}: Pick) { - const [inputValue, setInputValue] = useSafeState(value); - - useEffect(() => { - setInputValue(value); - }, [value]); - - const handleChange = (val: string) => { - setInputValue(val); - onChange?.(val); - }; - - const LabelComp = useMemo(() => { - if (label) { - if (typeof label === 'string') { - return ( - - {required && *} - - {label} - - - ); - } - return ( - - {required && *} - {label} - - ); - } - return null; - }, [label, required]); - - return { - inputValue, - handleChange, - LabelComp, - }; -} diff --git a/packages/react-native/src/list-item/index.tsx b/packages/react-native/src/list-item/index.tsx index 1158975548..b65b651192 100644 --- a/packages/react-native/src/list-item/index.tsx +++ b/packages/react-native/src/list-item/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, memo, PropsWithChildren, ReactElement, ReactNode } from 'react'; +import React, { FC, memo, PropsWithChildren, ReactElement, ReactNode, useMemo } from 'react'; import { Keyboard, StyleProp, ViewStyle } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -44,9 +44,7 @@ export type ListItemProps = { backgroundColor?: string; }; -type BriefBasePropsType = PropsWithChildren>; - -const Brief: FC = props => { +const Brief: FC>> = props => { const { children, wrap } = props; const numberOfLines = wrap ? {} : { numberOfLines: 1 }; return ( @@ -75,21 +73,58 @@ const ListItem = ({ required = false, activeOpacity = 0.6, }: ListItemProps) => { + if (!onPress) + return ( + + + + ); + + return ( + { + Keyboard.dismiss(); + onPress(); + }} + > + + + ); +}; +ListItem.displayName = 'ListItem'; + +export default memo(ListItem); + +const Content = ({ + backgroundColor, + style, + required, + thumb, + title, + brief, + wrap, + extra, + arrow, +}: Omit) => { const theme = useTheme(); - const renderTitle = () => ( - - {typeof title === 'string' ? ( - - {title} - - ) : ( - title - )} - + const Title = useMemo( + () => ( + + {typeof title === 'string' ? ( + + {title} + + ) : ( + title + )} + + ), + [thumb, title] ); - const renderExtra = () => { + const Extra = useMemo(() => { if (!extra) return null; if (typeof extra === 'string') { const numberOfLines = wrap ? {} : { numberOfLines: 1 }; @@ -108,9 +143,9 @@ const ListItem = ({ ); } return extra; - }; + }, [extra, wrap]); - const renderArrow = () => { + const Arrow = useMemo(() => { if (!arrow) return null; if (typeof arrow === 'string') return ( @@ -119,9 +154,9 @@ const ListItem = ({ ); return arrow; - }; + }, [arrow, theme.colors.icon]); - const renderContent = () => ( + return ( )} {thumb} - {renderTitle()} + {Title} - {renderExtra()} + {Extra} {!!brief && {brief}} - {renderArrow()} + {Arrow} ); - - if (!onPress) return {renderContent()}; - - return ( - { - Keyboard.dismiss(); - onPress(); - }} - > - {renderContent()} - - ); }; -ListItem.displayName = 'ListItem'; - -export default memo(ListItem); diff --git a/packages/react-native/src/list/index.tsx b/packages/react-native/src/list/index.tsx index 96c9dcfdbe..cdf5745a48 100644 --- a/packages/react-native/src/list/index.tsx +++ b/packages/react-native/src/list/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, ReactNode } from 'react'; +import React, { FC, memo, ReactNode, useMemo } from 'react'; import { StyleProp, TextStyle, ViewStyle } from 'react-native'; import Box from '../box'; @@ -20,17 +20,17 @@ type ListProps = { itemBackgroundColor?: string; }; const List: FC = ({ header, extra, itemBackgroundColor, items = [] }) => { - const renderHeader = () => { + const Header = useMemo(() => { if (!header) return null; if (typeof header === 'string') { return ; } return header; - }; + }, [header, extra]); return ( - {renderHeader()} + {Header} {items.map((props, index) => { return ; })} @@ -39,42 +39,44 @@ const List: FC = ({ header, extra, itemBackgroundColor, items = [] }) }; List.displayName = 'List'; -const ListHeader = ({ - text, - extra, - textStyle, - headerStyle, -}: { - /** 标题文本 */ - text: string; - /** 自定义右侧内容 */ - extra?: ReactNode; - /** 文本样式 */ - textStyle?: StyleProp; - /** 标题样式 */ - headerStyle?: StyleProp; -}) => { - if (text === '') return null; - return ( - - - - {text} - - - {extra} - - ); -}; +const ListHeader = memo( + ({ + text, + extra, + textStyle, + headerStyle, + }: { + /** 标题文本 */ + text: string; + /** 自定义右侧内容 */ + extra?: ReactNode; + /** 文本样式 */ + textStyle?: StyleProp; + /** 标题样式 */ + headerStyle?: StyleProp; + }) => { + if (text === '') return null; + return ( + + + + {text} + + + {extra} + + ); + } +); ListHeader.displayName = 'ListHeader'; export default Object.assign(List, { ListHeader }); diff --git a/packages/react-native/src/menu/Chevron.tsx b/packages/react-native/src/menu/Chevron.tsx index fe3ef6270a..b6c65e3d39 100644 --- a/packages/react-native/src/menu/Chevron.tsx +++ b/packages/react-native/src/menu/Chevron.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import Animated, { useAnimatedStyle } from 'react-native-reanimated'; import { mix } from 'react-native-redash'; @@ -20,4 +20,4 @@ const Chevron: FC<{ progress: Animated.SharedValue }> = ({ progress }) = ); }; -export default Chevron; +export default memo(Chevron); diff --git a/packages/react-native/src/menu/MenuGroup.tsx b/packages/react-native/src/menu/MenuGroup.tsx index 463a5bb1b8..c91e8446e9 100644 --- a/packages/react-native/src/menu/MenuGroup.tsx +++ b/packages/react-native/src/menu/MenuGroup.tsx @@ -1,4 +1,4 @@ -import React, { PropsWithChildren } from 'react'; +import React, { memo, PropsWithChildren } from 'react'; import Animated from 'react-native-reanimated'; import { useTheme } from '@shopify/restyle'; @@ -67,4 +67,4 @@ const MenuGroup = ({ }; MenuGroup.displayName = 'MenuGroup'; -export default MenuGroup; +export default memo(MenuGroup); diff --git a/packages/react-native/src/menu/useGroup.ts b/packages/react-native/src/menu/useGroup.ts index 9bfce5b7c6..1d91ff9078 100644 --- a/packages/react-native/src/menu/useGroup.ts +++ b/packages/react-native/src/menu/useGroup.ts @@ -49,7 +49,7 @@ export default function useGroup({ bodyStyle, progress, - handleLayout: useMemoizedFn(handleLayout), + handleLayout, handlePress: useMemoizedFn(handlePress), }; } diff --git a/packages/react-native/src/notice-bar/AnimatedNotice.tsx b/packages/react-native/src/notice-bar/AnimatedNotice.tsx index 8e24a53b10..9e96f5dc96 100644 --- a/packages/react-native/src/notice-bar/AnimatedNotice.tsx +++ b/packages/react-native/src/notice-bar/AnimatedNotice.tsx @@ -1,4 +1,4 @@ -import React, { FC, useEffect, useState } from 'react'; +import React, { FC, memo, useEffect, useState } from 'react'; import { LayoutChangeEvent } from 'react-native'; import Animated, { Easing, @@ -94,4 +94,4 @@ const AnimatedNotice: FC = props => { const [visible, setVisible] = useState(true); const [height, setHeight] = useState(0); - const onContentLayout = useMemoizedFn(e => { + const handleContentLayout = (e: LayoutChangeEvent) => { setHeight(e.nativeEvent.layout.height); - }); + }; if (!visible) return null; - const BaseContent = ; - - const WrapComp = ({ children }: PropsWithChildren<{}>) => { - if (onPress) - return ( - - {children} - - ); - return <>{children}; - }; + const BaseContent = ( + + ); switch (mode) { case 'close': return ( - + = props => { case 'link': return ( - + {BaseContent} = props => { default: return ( - + {BaseContent} @@ -120,3 +112,17 @@ const NoticeBar: FC = props => { NoticeBar.displayName = 'NoticeBar'; export default NoticeBar; + +const WrapComp = ({ + children, + onPress, + activeOpacity, +}: PropsWithChildren>) => { + if (onPress) + return ( + + {children} + + ); + return <>{children}; +}; diff --git a/packages/react-native/src/notify/NotifyRoot.tsx b/packages/react-native/src/notify/NotifyRoot.tsx index 9d224cec55..bc181f0824 100644 --- a/packages/react-native/src/notify/NotifyRoot.tsx +++ b/packages/react-native/src/notify/NotifyRoot.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef, useImperativeHandle } from 'react'; +import React, { forwardRef, useImperativeHandle, useMemo } from 'react'; import { StyleSheet } from 'react-native'; import Animated from 'react-native-reanimated'; import { useSafeAreaInsets } from 'react-native-safe-area-context'; @@ -11,6 +11,7 @@ import Pressable from '../pressable'; import SvgIcon from '../svg-icon'; import Text from '../text'; import { normalShadowOpt, NotifyType } from './constant'; +import { NotifyProps } from './type'; import useNotify from './useNotify'; const { px, hexToRgba } = helpers; @@ -36,73 +37,83 @@ const NotifyRoot = forwardRef((_, ref) => { zIndex: 49, bottom: -insets.bottom, }, + wrapper: { borderRadius: normalShadowOpt.radius, backgroundColor: bgColor }, + }); + + return ( + + + + + + + + ); +}); + +export default NotifyRoot; + +/** + * 渲染Notify内容。分为以下几种情况: + * 1. notify的类型不是INFO,这时候直接返回Content + * 2. notify类型是INFO: + * 1: onPress有值,Content被TouchableOpacity包裹,同时显示right图标; + * 如果同时onClose有值,再显示一个close图标,点击可关闭notify + * 2: onPress没有值,Contentbu包裹,不显示right图标; + * 如果同时onClose有值,再显示一个close图标,点击可关闭notify + */ +const Content = ({ + shadowColor, + options, + hide, +}: { + hide: () => void; + shadowColor: string; + options: NotifyProps & { type: NotifyType }; +}) => { + const styles = StyleSheet.create({ content: { flexDirection: 'row', justifyContent: 'center', alignItems: 'center', }, - wrapper: { borderRadius: normalShadowOpt.radius, backgroundColor: bgColor }, }); - const Content = ( - - {options.type === NotifyType.SUCCESS && ( - - - - )} - {options.type === NotifyType.FAIL && ( - - + const BaseContent = useMemo( + () => ( + + {options.type === NotifyType.SUCCESS && ( + + + + )} + {options.type === NotifyType.FAIL && ( + + + + )} + + {options.content} - )} - - {options.content} - - + + ), + [options.type, options.content, shadowColor] ); - /** - * 渲染Notify内容。分为以下几种情况: - * 1. notify的类型不是INFO,这时候直接返回Content - * 2. notify类型是INFO: - * 1: onPress有值,Content被TouchableOpacity包裹,同时显示right图标; - * 如果同时onClose有值,再显示一个close图标,点击可关闭notify - * 2: onPress没有值,Contentbu包裹,不显示right图标; - * 如果同时onClose有值,再显示一个close图标,点击可关闭notify - */ - const renderContent = () => { - if (options.type !== NotifyType.INFO) return Content; - - if (options.onPress) { - if (options.onClose) { - return ( - - {Content} - { - e.stopPropagation(); - hide(); - }} - > - - - - - ); - } - return ( - - {Content} - - - ); - } + if (options.type !== NotifyType.INFO) return BaseContent; + if (options.onPress) { if (options.onClose) { return ( - - {Content} + + {BaseContent} { e.stopPropagation(); @@ -111,28 +122,32 @@ const NotifyRoot = forwardRef((_, ref) => { > - + + ); } - return Content; - }; + return ( + + {BaseContent} + + + ); + } - return ( - - - + {BaseContent} + { + e.stopPropagation(); + hide(); + }} > - {renderContent()} - - - - ); -}); - -export default NotifyRoot; + + + + ); + } + return BaseContent; +}; diff --git a/packages/react-native/src/pagination/index.tsx b/packages/react-native/src/pagination/index.tsx index 870efc5d1f..ec068b94ce 100644 --- a/packages/react-native/src/pagination/index.tsx +++ b/packages/react-native/src/pagination/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, ReactElement } from 'react'; +import React, { FC, ReactElement, useMemo } from 'react'; import Flex from '../flex'; import Pressable from '../pressable'; @@ -40,10 +40,15 @@ const Pagination: FC = ({ counterRender, activeOpacity = 0.6, }) => { - const { current, setCurrent, totalPage, isFirstPage, isLastPage } = usePagination({ page, pageSize, total }); + const { current, prev, next, totalPage, isFirstPage, isLastPage } = usePagination({ + page, + pageSize, + total, + onChange, + }); /** 渲染上一页按钮 */ - const renderPrevBtn = () => { + const PrevBtn = useMemo(() => { if (prevButtonRender) { return prevButtonRender(isFirstPage); } @@ -52,10 +57,10 @@ const Pagination: FC = ({ {prevButtonText} ); - }; + }, [isFirstPage, prevButtonRender, prevButtonText]); /** 渲染当前页 */ - const renderCurrent = () => { + const Current = useMemo(() => { if (counterRender) { return counterRender(current, totalPage); } @@ -70,10 +75,10 @@ const Pagination: FC = ({ ); - }; + }, [counterRender, current, totalPage]); /** 渲染下一页按钮 */ - const renderNextBtn = () => { + const NextBtn = useMemo(() => { if (nextButtonRender) { return nextButtonRender(isLastPage); } @@ -82,32 +87,16 @@ const Pagination: FC = ({ {nextButtonText} ); - }; - - /** 前一页 */ - const prev = () => { - const perPage = current - 1; - setCurrent(perPage); - onChange?.(perPage); - }; - - /** 后一页 */ - const next = () => { - const nextPage = current + 1; - setCurrent(nextPage); - onChange?.(nextPage); - }; + }, [isLastPage, nextButtonRender, nextButtonText]); return ( - {renderPrevBtn()} + {PrevBtn} - - {renderCurrent()} - + {Current} - {renderNextBtn()} + {NextBtn} ); diff --git a/packages/react-native/src/pagination/usePagination.ts b/packages/react-native/src/pagination/usePagination.ts index a8c8407812..25925c7f2b 100644 --- a/packages/react-native/src/pagination/usePagination.ts +++ b/packages/react-native/src/pagination/usePagination.ts @@ -1,6 +1,6 @@ import { useEffect } from 'react'; -import { useSafeState } from '@td-design/rn-hooks'; +import { useMemoizedFn, useSafeState } from '@td-design/rn-hooks'; import type { PaginationProps } from '.'; @@ -8,7 +8,8 @@ export default function usePagination({ page = 1, pageSize = 10, total, -}: Pick) { + onChange, +}: Pick) { const [current, setCurrent] = useSafeState(page); const [totalPage, setTotalPage] = useSafeState(Math.ceil(total / pageSize)); @@ -23,11 +24,27 @@ export default function usePagination({ const isFirstPage = current === 1; const isLastPage = current === totalPage; + /** 前一页 */ + const prev = () => { + const perPage = current - 1; + setCurrent(perPage); + onChange?.(perPage); + }; + + /** 后一页 */ + const next = () => { + const nextPage = current + 1; + setCurrent(nextPage); + onChange?.(nextPage); + }; + return { current, - setCurrent, totalPage, isFirstPage, isLastPage, + + prev: useMemoizedFn(prev), + next: useMemoizedFn(next), }; } diff --git a/packages/react-native/src/pressable/index.tsx b/packages/react-native/src/pressable/index.tsx index e4781cc8d5..e892899437 100644 --- a/packages/react-native/src/pressable/index.tsx +++ b/packages/react-native/src/pressable/index.tsx @@ -29,7 +29,7 @@ * effect is the invocation of `onPress` and `onLongPress` that occur when a * responder is release while in the "press in" states. */ -import React, { PropsWithChildren } from 'react'; +import React, { memo, PropsWithChildren } from 'react'; import { Pressable as RNPressable, PressableProps as RNPressableProps, StyleProp, ViewStyle } from 'react-native'; import helpers from '../helpers'; @@ -58,36 +58,33 @@ export interface PressableProps } const { px } = helpers; -class Pressable extends React.Component> { - static displayName = 'Pressable'; +function Pressable(props: PropsWithChildren) { + const { + children, + activeOpacity = 0.6, + pressOffset = px(20), + hitOffset, + delayLongPress = 1000, + style, + ...rest + } = props; - render() { - const { - children, - activeOpacity = 0.6, - pressOffset = px(20), - hitOffset, - delayLongPress = 1000, - style, - ...rest - } = this.props; + if (!children) return null; - if (!children) return null; - - return ( - [{ opacity: pressed ? activeOpacity : 1 }, style]} - {...rest} - > - {children} - - ); - } + return ( + [{ opacity: pressed ? activeOpacity : 1 }, style]} + {...rest} + > + {children} + + ); } +Pressable.displayName = 'Pressable'; -export default Pressable; +export default memo(Pressable); diff --git a/packages/react-native/src/radio/RadioItem.tsx b/packages/react-native/src/radio/RadioItem.tsx index 3d4f179768..3ca9f22e3b 100644 --- a/packages/react-native/src/radio/RadioItem.tsx +++ b/packages/react-native/src/radio/RadioItem.tsx @@ -1,4 +1,4 @@ -import React, { FC, memo } from 'react'; +import React, { FC, memo, useMemo } from 'react'; import { Keyboard, StyleSheet } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -41,7 +41,7 @@ const RadioItem: FC = ({ list: { width: '100%', flex: 1 }, }); - const renderLabel = () => { + const Label = useMemo(() => { if (typeof label === 'string') { return ( @@ -50,7 +50,7 @@ const RadioItem: FC = ({ ); } return label; - }; + }, [disabled, label, labelStyle]); if (!disabled) return ( @@ -63,7 +63,7 @@ const RadioItem: FC = ({ - {renderLabel()} + {Label} ); @@ -74,7 +74,7 @@ const RadioItem: FC = ({ - {renderLabel()} + {Label} ); diff --git a/packages/react-native/src/result/index.tsx b/packages/react-native/src/result/index.tsx index d50bc1fead..55a1909fdd 100644 --- a/packages/react-native/src/result/index.tsx +++ b/packages/react-native/src/result/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, ReactNode } from 'react'; +import React, { FC, memo, ReactNode, useMemo } from 'react'; import { Image, ImageSourcePropType, StyleProp, ViewStyle } from 'react-native'; import { SvgXml } from 'react-native-svg'; @@ -29,7 +29,7 @@ export interface ResultProps { } const Result: FC = ({ actions = [], type, title, content, imgSource, containerStyle }) => { - const renderImgByType = () => { + const ImgByType = useMemo(() => { if (imgSource) return ; switch (type) { @@ -42,9 +42,9 @@ const Result: FC = ({ actions = [], type, title, content, imgSource default: return null; } - }; + }, [imgSource, type]); - const renderTitle = () => { + const Title = useMemo(() => { if (!title) return null; if (typeof title === 'string') { return ( @@ -54,9 +54,9 @@ const Result: FC = ({ actions = [], type, title, content, imgSource ); } return title; - }; + }, [title]); - const renderContent = () => { + const Content = useMemo(() => { if (!content) return null; if (typeof content === 'string') { return ( @@ -66,13 +66,13 @@ const Result: FC = ({ actions = [], type, title, content, imgSource ); } return content; - }; + }, [content]); return ( - {renderImgByType()} - {renderTitle()} - {renderContent()} + {ImgByType} + {Title} + {Content} {actions.length > 0 && ( {actions.map((action, index) => ( @@ -89,7 +89,7 @@ Result.displayName = 'Result'; export default Result; -function SuccessImg() { +const SuccessImg = memo(() => { const xml = ` @@ -216,9 +216,9 @@ function SuccessImg() { `; return ; -} +}); -function FailImg() { +const FailImg = memo(() => { const xml = ` @@ -345,9 +345,9 @@ function FailImg() { `; return ; -} +}); -function ProcessImg() { +const ProcessImg = memo(() => { const xml = ` @@ -474,4 +474,4 @@ function ProcessImg() { `; return ; -} +}); diff --git a/packages/react-native/src/scroll-number/index.tsx b/packages/react-native/src/scroll-number/index.tsx index 59c9b1a2c5..7e117f7e33 100644 --- a/packages/react-native/src/scroll-number/index.tsx +++ b/packages/react-native/src/scroll-number/index.tsx @@ -1,9 +1,9 @@ -import React, { FC, useCallback } from 'react'; +import React, { FC, memo } from 'react'; import { LayoutChangeEvent, StyleProp, StyleSheet, TextStyle, ViewStyle } from 'react-native'; import Animated, { useAnimatedStyle, withSpring, withTiming } from 'react-native-reanimated'; import { useTheme } from '@shopify/restyle'; -import { useBoolean, useSafeState } from '@td-design/rn-hooks'; +import { useBoolean, useMemoizedFn, useSafeState } from '@td-design/rn-hooks'; import Box from '../box'; import Flex from '../flex'; @@ -44,15 +44,12 @@ const ScrollNumber: FC = ({ const [measured, { setTrue }] = useBoolean(!!height); const [currentHeight, setCurrentHeight] = useSafeState(height); - const handleLayout = useCallback( - (e: LayoutChangeEvent) => { - if (height) return; - const layoutHeight = e.nativeEvent.layout.height; - setCurrentHeight(layoutHeight); - setTrue(); - }, - [height] - ); + const handleLayout = useMemoizedFn((e: LayoutChangeEvent) => { + if (height) return; + const layoutHeight = e.nativeEvent.layout.height; + setCurrentHeight(layoutHeight); + setTrue(); + }); const styles = StyleSheet.create({ height: { @@ -93,7 +90,7 @@ export interface TickProps value: string; height: number; } -const Tick: FC = ({ numberRange, value, height, containerStyle, textStyle, animationType }) => { +const Tick: FC = memo(({ numberRange, value, height, containerStyle, textStyle, animationType }) => { const getPosition = (value: string, height: number) => { 'worklet'; const index = numberRange?.findIndex(item => item === value); @@ -125,4 +122,4 @@ const Tick: FC = ({ numberRange, value, height, containerStyle, textS ))} ); -}; +}); diff --git a/packages/react-native/src/search-bar/index.tsx b/packages/react-native/src/search-bar/index.tsx index eaa916069b..5dada4c5d9 100644 --- a/packages/react-native/src/search-bar/index.tsx +++ b/packages/react-native/src/search-bar/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, PropsWithChildren } from 'react'; +import React, { FC, PropsWithChildren, useMemo } from 'react'; import { KeyboardTypeOptions, ReturnKeyTypeOptions, StyleProp, StyleSheet, TextStyle, ViewStyle } from 'react-native'; import Animated, { FadeInRight, FadeOutRight } from 'react-native-reanimated'; @@ -89,7 +89,7 @@ const SearchBar: FC = props => { }, }); - const renderCancelBtn = () => { + const CancelBtn = useMemo(() => { if (!showCancelButton || !focused) return null; return ( = props => { ); - }; + }, [showCancelButton, focused, activeOpacity, theme.spacing.x2, cancelText, onCancel]); return ( @@ -139,7 +139,7 @@ const SearchBar: FC = props => { onSubmitEditing={e => onSearch?.(e.nativeEvent.text)} /> {/* 取消按钮 */} - {renderCancelBtn()} + {CancelBtn} ); }; diff --git a/packages/react-native/src/slider/index.tsx b/packages/react-native/src/slider/index.tsx index 385da87656..2c72dcd117 100644 --- a/packages/react-native/src/slider/index.tsx +++ b/packages/react-native/src/slider/index.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { StyleSheet, TextStyle } from 'react-native'; import { PanGestureHandler } from 'react-native-gesture-handler'; import Animated from 'react-native-reanimated'; @@ -101,20 +101,26 @@ const Slider: FC = props => { }, }); - const SliderContent = ( - - - - - - + const SliderContent = useMemo( + () => ( + + + + + + + ), + [width, KNOB_WIDTH, progressStyle, onGestureEvent, knobStyle] ); if (!showLabel) { return SliderContent; } - const Label = ; + const Label = useMemo( + () => , + [label, labelStyle] + ); if (labelPosition === 'top' || labelPosition === 'bottom') { return ( diff --git a/packages/react-native/src/svg-icon/IconArrowdown.tsx b/packages/react-native/src/svg-icon/IconArrowdown.tsx index 5f36f6f59d..67f913f58c 100644 --- a/packages/react-native/src/svg-icon/IconArrowdown.tsx +++ b/packages/react-native/src/svg-icon/IconArrowdown.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -36,6 +33,4 @@ IconArrowdown.defaultProps = { size: px(16), }; -IconArrowdown = React.memo ? React.memo(IconArrowdown) : IconArrowdown; - -export default IconArrowdown; +export default memo(IconArrowdown); diff --git a/packages/react-native/src/svg-icon/IconBells.tsx b/packages/react-native/src/svg-icon/IconBells.tsx index 180cf3f198..409914b313 100644 --- a/packages/react-native/src/svg-icon/IconBells.tsx +++ b/packages/react-native/src/svg-icon/IconBells.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -36,6 +33,4 @@ IconBells.defaultProps = { size: px(16), }; -IconBells = React.memo ? React.memo(IconBells) : IconBells; - -export default IconBells; +export default memo(IconBells); diff --git a/packages/react-native/src/svg-icon/IconCheck.tsx b/packages/react-native/src/svg-icon/IconCheck.tsx index e964c29b59..af40631557 100644 --- a/packages/react-native/src/svg-icon/IconCheck.tsx +++ b/packages/react-native/src/svg-icon/IconCheck.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconCheck.defaultProps = { size: px(16), }; -IconCheck = React.memo ? React.memo(IconCheck) : IconCheck; - -export default IconCheck; +export default memo(IconCheck); diff --git a/packages/react-native/src/svg-icon/IconCheckboxChecked.tsx b/packages/react-native/src/svg-icon/IconCheckboxChecked.tsx index a9ad164022..a5e4047a7c 100644 --- a/packages/react-native/src/svg-icon/IconCheckboxChecked.tsx +++ b/packages/react-native/src/svg-icon/IconCheckboxChecked.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconCheckboxChecked.defaultProps = { size: px(16), }; -IconCheckboxChecked = React.memo ? React.memo(IconCheckboxChecked) : IconCheckboxChecked; - -export default IconCheckboxChecked; +export default memo(IconCheckboxChecked); diff --git a/packages/react-native/src/svg-icon/IconCheckboxHalfchecked.tsx b/packages/react-native/src/svg-icon/IconCheckboxHalfchecked.tsx index afc5904e02..dd558414db 100644 --- a/packages/react-native/src/svg-icon/IconCheckboxHalfchecked.tsx +++ b/packages/react-native/src/svg-icon/IconCheckboxHalfchecked.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconCheckboxHalfchecked.defaultProps = { size: px(16), }; -IconCheckboxHalfchecked = React.memo ? React.memo(IconCheckboxHalfchecked) : IconCheckboxHalfchecked; - -export default IconCheckboxHalfchecked; +export default memo(IconCheckboxHalfchecked); diff --git a/packages/react-native/src/svg-icon/IconCheckboxUnchecked.tsx b/packages/react-native/src/svg-icon/IconCheckboxUnchecked.tsx index 66986778f7..588586be36 100644 --- a/packages/react-native/src/svg-icon/IconCheckboxUnchecked.tsx +++ b/packages/react-native/src/svg-icon/IconCheckboxUnchecked.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconCheckboxUnchecked.defaultProps = { size: px(16), }; -IconCheckboxUnchecked = React.memo ? React.memo(IconCheckboxUnchecked) : IconCheckboxUnchecked; - -export default IconCheckboxUnchecked; +export default memo(IconCheckboxUnchecked); diff --git a/packages/react-native/src/svg-icon/IconCheckcircle.tsx b/packages/react-native/src/svg-icon/IconCheckcircle.tsx index bcb6921638..f761e0e412 100644 --- a/packages/react-native/src/svg-icon/IconCheckcircle.tsx +++ b/packages/react-native/src/svg-icon/IconCheckcircle.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconCheckcircle.defaultProps = { size: px(16), }; -IconCheckcircle = React.memo ? React.memo(IconCheckcircle) : IconCheckcircle; - -export default IconCheckcircle; +export default memo(IconCheckcircle); diff --git a/packages/react-native/src/svg-icon/IconCheckcircleo.tsx b/packages/react-native/src/svg-icon/IconCheckcircleo.tsx index 00fa7a1154..c1d23e7acb 100644 --- a/packages/react-native/src/svg-icon/IconCheckcircleo.tsx +++ b/packages/react-native/src/svg-icon/IconCheckcircleo.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -41,6 +38,4 @@ IconCheckcircleo.defaultProps = { size: px(16), }; -IconCheckcircleo = React.memo ? React.memo(IconCheckcircleo) : IconCheckcircleo; - -export default IconCheckcircleo; +export default memo(IconCheckcircleo); diff --git a/packages/react-native/src/svg-icon/IconClockcircleo.tsx b/packages/react-native/src/svg-icon/IconClockcircleo.tsx index 1759b18d7f..00bf5b134d 100644 --- a/packages/react-native/src/svg-icon/IconClockcircleo.tsx +++ b/packages/react-native/src/svg-icon/IconClockcircleo.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -36,6 +33,4 @@ IconClockcircleo.defaultProps = { size: px(16), }; -IconClockcircleo = React.memo ? React.memo(IconClockcircleo) : IconClockcircleo; - -export default IconClockcircleo; +export default memo(IconClockcircleo); diff --git a/packages/react-native/src/svg-icon/IconClose.tsx b/packages/react-native/src/svg-icon/IconClose.tsx index b7148ec7ae..05a9742a56 100644 --- a/packages/react-native/src/svg-icon/IconClose.tsx +++ b/packages/react-native/src/svg-icon/IconClose.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconClose.defaultProps = { size: px(16), }; -IconClose = React.memo ? React.memo(IconClose) : IconClose; - -export default IconClose; +export default memo(IconClose); diff --git a/packages/react-native/src/svg-icon/IconClosecircleo.tsx b/packages/react-native/src/svg-icon/IconClosecircleo.tsx index 27f3cbfc1c..b71c5a68d5 100644 --- a/packages/react-native/src/svg-icon/IconClosecircleo.tsx +++ b/packages/react-native/src/svg-icon/IconClosecircleo.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconClosecircleo.defaultProps = { size: px(16), }; -IconClosecircleo = React.memo ? React.memo(IconClosecircleo) : IconClosecircleo; - -export default IconClosecircleo; +export default memo(IconClosecircleo); diff --git a/packages/react-native/src/svg-icon/IconDate.tsx b/packages/react-native/src/svg-icon/IconDate.tsx index 6b4419aa83..94536d5471 100644 --- a/packages/react-native/src/svg-icon/IconDate.tsx +++ b/packages/react-native/src/svg-icon/IconDate.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -76,6 +73,4 @@ IconDate.defaultProps = { size: px(16), }; -IconDate = React.memo ? React.memo(IconDate) : IconDate; - -export default IconDate; +export default memo(IconDate); diff --git a/packages/react-native/src/svg-icon/IconDown.tsx b/packages/react-native/src/svg-icon/IconDown.tsx index 3567d1ca3a..693a5592a8 100644 --- a/packages/react-native/src/svg-icon/IconDown.tsx +++ b/packages/react-native/src/svg-icon/IconDown.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconDown.defaultProps = { size: px(16), }; -IconDown = React.memo ? React.memo(IconDown) : IconDown; - -export default IconDown; +export default memo(IconDown); diff --git a/packages/react-native/src/svg-icon/IconEllipsis.tsx b/packages/react-native/src/svg-icon/IconEllipsis.tsx index 5ebc6587e9..5e5061ce76 100644 --- a/packages/react-native/src/svg-icon/IconEllipsis.tsx +++ b/packages/react-native/src/svg-icon/IconEllipsis.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconEllipsis.defaultProps = { size: px(16), }; -IconEllipsis = React.memo ? React.memo(IconEllipsis) : IconEllipsis; - -export default IconEllipsis; +export default memo(IconEllipsis); diff --git a/packages/react-native/src/svg-icon/IconEyeclose.tsx b/packages/react-native/src/svg-icon/IconEyeclose.tsx index 18efb956aa..15da117764 100644 --- a/packages/react-native/src/svg-icon/IconEyeclose.tsx +++ b/packages/react-native/src/svg-icon/IconEyeclose.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -51,6 +48,4 @@ IconEyeclose.defaultProps = { size: px(16), }; -IconEyeclose = React.memo ? React.memo(IconEyeclose) : IconEyeclose; - -export default IconEyeclose; +export default memo(IconEyeclose); diff --git a/packages/react-native/src/svg-icon/IconEyeopen.tsx b/packages/react-native/src/svg-icon/IconEyeopen.tsx index 026bc73a32..c35aa3e16d 100644 --- a/packages/react-native/src/svg-icon/IconEyeopen.tsx +++ b/packages/react-native/src/svg-icon/IconEyeopen.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -36,6 +33,4 @@ IconEyeopen.defaultProps = { size: px(16), }; -IconEyeopen = React.memo ? React.memo(IconEyeopen) : IconEyeopen; - -export default IconEyeopen; +export default memo(IconEyeopen); diff --git a/packages/react-native/src/svg-icon/IconLeft.tsx b/packages/react-native/src/svg-icon/IconLeft.tsx index a4d82e88d6..d390997c0e 100644 --- a/packages/react-native/src/svg-icon/IconLeft.tsx +++ b/packages/react-native/src/svg-icon/IconLeft.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconLeft.defaultProps = { size: px(16), }; -IconLeft = React.memo ? React.memo(IconLeft) : IconLeft; - -export default IconLeft; +export default memo(IconLeft); diff --git a/packages/react-native/src/svg-icon/IconMinus.tsx b/packages/react-native/src/svg-icon/IconMinus.tsx index 9cfaedcd14..e276b31de6 100644 --- a/packages/react-native/src/svg-icon/IconMinus.tsx +++ b/packages/react-native/src/svg-icon/IconMinus.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconMinus.defaultProps = { size: px(16), }; -IconMinus = React.memo ? React.memo(IconMinus) : IconMinus; - -export default IconMinus; +export default memo(IconMinus); diff --git a/packages/react-native/src/svg-icon/IconPlus.tsx b/packages/react-native/src/svg-icon/IconPlus.tsx index 1447ee4a54..3acd38ea24 100644 --- a/packages/react-native/src/svg-icon/IconPlus.tsx +++ b/packages/react-native/src/svg-icon/IconPlus.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconPlus.defaultProps = { size: px(16), }; -IconPlus = React.memo ? React.memo(IconPlus) : IconPlus; - -export default IconPlus; +export default memo(IconPlus); diff --git a/packages/react-native/src/svg-icon/IconRadioChecked.tsx b/packages/react-native/src/svg-icon/IconRadioChecked.tsx index 7b5317aaf9..d888106e7e 100644 --- a/packages/react-native/src/svg-icon/IconRadioChecked.tsx +++ b/packages/react-native/src/svg-icon/IconRadioChecked.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconRadioChecked.defaultProps = { size: px(16), }; -IconRadioChecked = React.memo ? React.memo(IconRadioChecked) : IconRadioChecked; - -export default IconRadioChecked; +export default memo(IconRadioChecked); diff --git a/packages/react-native/src/svg-icon/IconRadioUnchecked.tsx b/packages/react-native/src/svg-icon/IconRadioUnchecked.tsx index 166c72d306..f75905a557 100644 --- a/packages/react-native/src/svg-icon/IconRadioUnchecked.tsx +++ b/packages/react-native/src/svg-icon/IconRadioUnchecked.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconRadioUnchecked.defaultProps = { size: px(16), }; -IconRadioUnchecked = React.memo ? React.memo(IconRadioUnchecked) : IconRadioUnchecked; - -export default IconRadioUnchecked; +export default memo(IconRadioUnchecked); diff --git a/packages/react-native/src/svg-icon/IconReload.tsx b/packages/react-native/src/svg-icon/IconReload.tsx index 8ea4d07243..f8929f84fc 100644 --- a/packages/react-native/src/svg-icon/IconReload.tsx +++ b/packages/react-native/src/svg-icon/IconReload.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconReload.defaultProps = { size: px(16), }; -IconReload = React.memo ? React.memo(IconReload) : IconReload; - -export default IconReload; +export default memo(IconReload); diff --git a/packages/react-native/src/svg-icon/IconRight.tsx b/packages/react-native/src/svg-icon/IconRight.tsx index a455f4c875..1da9894db8 100644 --- a/packages/react-native/src/svg-icon/IconRight.tsx +++ b/packages/react-native/src/svg-icon/IconRight.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconRight.defaultProps = { size: px(16), }; -IconRight = React.memo ? React.memo(IconRight) : IconRight; - -export default IconRight; +export default memo(IconRight); diff --git a/packages/react-native/src/svg-icon/IconSearch.tsx b/packages/react-native/src/svg-icon/IconSearch.tsx index d753968070..643402f625 100644 --- a/packages/react-native/src/svg-icon/IconSearch.tsx +++ b/packages/react-native/src/svg-icon/IconSearch.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -36,6 +33,4 @@ IconSearch.defaultProps = { size: px(16), }; -IconSearch = React.memo ? React.memo(IconSearch) : IconSearch; - -export default IconSearch; +export default memo(IconSearch); diff --git a/packages/react-native/src/svg-icon/IconUp.tsx b/packages/react-native/src/svg-icon/IconUp.tsx index cb1db724ea..a3632032a4 100644 --- a/packages/react-native/src/svg-icon/IconUp.tsx +++ b/packages/react-native/src/svg-icon/IconUp.tsx @@ -1,7 +1,4 @@ -/* tslint:disable */ - -/* eslint-disable */ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { ViewProps } from 'react-native'; import { GProps, SvgXml } from 'react-native-svg'; @@ -31,6 +28,4 @@ IconUp.defaultProps = { size: px(16), }; -IconUp = React.memo ? React.memo(IconUp) : IconUp; - -export default IconUp; +export default memo(IconUp); diff --git a/packages/react-native/src/swipe-row/context.tsx b/packages/react-native/src/swipe-row/context.tsx index 925cd9045d..3eaa86dc8f 100644 --- a/packages/react-native/src/swipe-row/context.tsx +++ b/packages/react-native/src/swipe-row/context.tsx @@ -1,26 +1,34 @@ -import React, { PropsWithChildren, useCallback, useMemo } from 'react'; +import React, { PropsWithChildren, useMemo } from 'react'; -import { usePrevious, useSafeState } from '@td-design/rn-hooks'; +import { useMemoizedFn, usePrevious, useSafeState } from '@td-design/rn-hooks'; export const SwipeRowContext = React.createContext<{ id?: string | number; changeState: (id: string | number) => void; + multiple?: boolean; }>({ id: undefined, changeState: (id: string | number) => { console.log('id', id); }, + multiple: false, }); -export const SwipeRowContextProvider = ({ children }: PropsWithChildren) => { +export const SwipeRowContextProvider = ({ + children, + multiple, +}: PropsWithChildren<{ + /** 是否允许多开 */ + multiple?: boolean; +}>) => { const [currentId, setCurrentId] = useSafeState(''); const previous = usePrevious(currentId); - const changeState = useCallback((id: string | number) => { + const changeState = useMemoizedFn((id: string | number) => { setCurrentId(id); - }, []); + }); - const value = useMemo(() => ({ changeState, id: previous }), [previous]); + const value = useMemo(() => ({ changeState, id: previous, multiple }), [previous, multiple]); return {children}; }; diff --git a/packages/react-native/src/swipe-row/index.tsx b/packages/react-native/src/swipe-row/index.tsx index 2a770e0394..96cc09eb70 100644 --- a/packages/react-native/src/swipe-row/index.tsx +++ b/packages/react-native/src/swipe-row/index.tsx @@ -78,7 +78,7 @@ const SwipeRow: FC = ({ }); return ( - + {props.label} diff --git a/packages/react-native/src/swipe-row/useSwipeRow.ts b/packages/react-native/src/swipe-row/useSwipeRow.ts index 7945895754..5d67af2754 100644 --- a/packages/react-native/src/swipe-row/useSwipeRow.ts +++ b/packages/react-native/src/swipe-row/useSwipeRow.ts @@ -8,15 +8,15 @@ import { SwipeRowContext } from './context'; export default function useSwipeRow({ anchor, onRemove }: Pick) { const swipeableRef = useRef(null); - const { changeState, id } = useContext(SwipeRowContext); + const { changeState, id, multiple } = useContext(SwipeRowContext); const [visible, setVisible] = useSafeState(true); useEffect(() => { - if (anchor === id) { + if (anchor === id && !multiple) { swipeableRef.current?.close(); } - }, [anchor, id]); + }, [anchor, id, multiple]); const handleRemove = async () => { await onRemove?.(); diff --git a/packages/react-native/src/switch/index.tsx b/packages/react-native/src/switch/index.tsx index 70b2b11be1..86b2541f9b 100644 --- a/packages/react-native/src/switch/index.tsx +++ b/packages/react-native/src/switch/index.tsx @@ -1,4 +1,4 @@ -import React, { forwardRef } from 'react'; +import React, { forwardRef, useMemo } from 'react'; import { StyleSheet, TouchableWithoutFeedback } from 'react-native'; import Animated, { useAnimatedStyle } from 'react-native-reanimated'; import { mix, mixColor } from 'react-native-redash'; @@ -95,7 +95,7 @@ const Switch = forwardRef( text: { fontSize: HANDLER_SIZE / 2, color: theme.colors.primary200 }, }); - const renderContent = () => { + const Content = useMemo(() => { return ( @@ -111,12 +111,12 @@ const Switch = forwardRef( ); - }; + }, [checked, disabled, showText, onText, offText, containerStyle, handlerStyle]); if (disabled) { - return renderContent(); + return Content; } - return {renderContent()}; + return {Content}; } ); Switch.displayName = 'Switch'; diff --git a/packages/react-native/src/table/Cell.tsx b/packages/react-native/src/table/Cell.tsx index d8996eede6..61b051b0fa 100644 --- a/packages/react-native/src/table/Cell.tsx +++ b/packages/react-native/src/table/Cell.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { StyleProp, ViewStyle } from 'react-native'; import Box from '../box'; @@ -11,7 +11,7 @@ interface CellProps { style?: StyleProp; } -export const Cell: FC = ({ data, column, style }) => { +export const Cell: FC = memo(({ data, column, style }) => { return ( {column.render ? ( @@ -37,4 +37,4 @@ export const Cell: FC = ({ data, column, style }) => { )} ); -}; +}); diff --git a/packages/react-native/src/table/Head.tsx b/packages/react-native/src/table/Head.tsx index 4a00b7adfc..1076318324 100644 --- a/packages/react-native/src/table/Head.tsx +++ b/packages/react-native/src/table/Head.tsx @@ -1,4 +1,4 @@ -import React, { FC, useContext, useMemo } from 'react'; +import React, { FC, memo, useContext, useMemo } from 'react'; import { StyleProp, ViewStyle } from 'react-native'; import Box from '../box'; @@ -12,7 +12,7 @@ interface HeadProps { headerStyle?: StyleProp; } -export const Head: FC = ({ headerStyle }) => { +export const Head: FC = memo(({ headerStyle }) => { const { columns, cellWidth } = useContext(ColumnContext); const cellRender = useMemo(() => { @@ -49,4 +49,4 @@ export const Head: FC = ({ headerStyle }) => { {cellRender} ); -}; +}); diff --git a/packages/react-native/src/table/Rows.tsx b/packages/react-native/src/table/Rows.tsx index dd1c26ee26..d6e6f03c20 100644 --- a/packages/react-native/src/table/Rows.tsx +++ b/packages/react-native/src/table/Rows.tsx @@ -1,4 +1,4 @@ -import React, { FC, useContext, useMemo } from 'react'; +import React, { FC, memo, useContext, useMemo } from 'react'; import { StyleProp, ViewStyle } from 'react-native'; import Box from '../box'; @@ -13,7 +13,7 @@ interface RowsProps { rowStyle?: StyleProp; } -export const Rows: FC = ({ data, rowStyle }) => { +export const Rows: FC = memo(({ data, rowStyle }) => { const { columns, cellWidth } = useContext(ColumnContext); const cellRender = useMemo(() => { @@ -39,4 +39,4 @@ export const Rows: FC = ({ data, rowStyle }) => { {cellRender} ); -}; +}); diff --git a/packages/react-native/src/table/index.tsx b/packages/react-native/src/table/index.tsx index 131447ea82..8700a9a39c 100644 --- a/packages/react-native/src/table/index.tsx +++ b/packages/react-native/src/table/index.tsx @@ -48,7 +48,7 @@ function Table>(props: TableProps) { horizontal onContentSizeChange={handleLayout} contentContainerStyle={styles.contentContainer} - showsHorizontalScrollIndicator={true} + showsHorizontalScrollIndicator={false} showsVerticalScrollIndicator={false} scrollEnabled={true} bounces={false} @@ -57,6 +57,8 @@ function Table>(props: TableProps) { scrollEnabled={dataSource.length > 0} nestedScrollEnabled stickyHeaderIndices={fixedHeader && showHeader ? [0] : []} + showsVerticalScrollIndicator={false} + showsHorizontalScrollIndicator={false} contentContainerStyle={{ flexGrow: 1, backgroundColor: theme.colors.white, diff --git a/packages/react-native/src/tag/index.tsx b/packages/react-native/src/tag/index.tsx index cd11827aac..aea8296bbd 100644 --- a/packages/react-native/src/tag/index.tsx +++ b/packages/react-native/src/tag/index.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, useMemo } from 'react'; import { StyleSheet } from 'react-native'; import Svg, { Path } from 'react-native-svg'; @@ -53,6 +53,7 @@ type BaseTagProps = BorderProps & ColorProps & LayoutProps & TypographyProps; + const BaseTag = createRestyleComponent([border, backgroundColor, color, layout, typography]); const { px, ONE_PIXEL } = helpers; @@ -75,6 +76,35 @@ const Tag: FC = ({ if (closed) return null; + const { + fontFamily, + fontSize = px(12), + fontStyle, + fontWeight, + letterSpacing, + lineHeight, + textAlign, + textDecorationLine, + textDecorationStyle, + textTransform, + color = disabled ? 'disabled' : 'primary100', + backgroundColor, + borderWidth = ONE_PIXEL, + justifyContent = 'center', + alignItems = 'center', + borderRadius = 'x1', + ...rest + } = restProps; + + let borderColor = rest.borderColor ?? color; + if (ghost && disabled) { + borderColor = 'disabled'; + } else if (checked) { + borderColor = 'primary200'; + } + + const { paddingHorizontal, paddingVertical } = getBySize(size); + const styles = StyleSheet.create({ iconBtn: { position: 'absolute', @@ -97,20 +127,20 @@ const Tag: FC = ({ }); /** 删除的图标组件 */ - const renderClosableIcon = () => { + const ClosableIcon = useMemo(() => { if (closable && !disabled) return ( - handleDelete()} style={styles.iconBtn}> + ); return null; - }; + }, [closable, disabled, styles.iconBtn, styles.iconWrap, theme.colors.white]); /** 选中的图标组件 */ - const renderCheckedIcon = () => { + const CheckedIcon = useMemo(() => { if (checked) return ( @@ -123,9 +153,9 @@ const Tag: FC = ({ ); return null; - }; + }, [checked, styles.check, theme.colors.primary200]); - const renderContent = () => ( + const Content = ( = ({ ); - const { - fontFamily, - fontSize = px(12), - fontStyle, - fontWeight, - letterSpacing, - lineHeight, - textAlign, - textDecorationLine, - textDecorationStyle, - textTransform, - color = disabled ? 'disabled' : 'primary100', - backgroundColor, - borderWidth = ONE_PIXEL, - justifyContent = 'center', - alignItems = 'center', - borderRadius = 'x1', - ...rest - } = restProps; - - let borderColor = rest.borderColor ?? color; - if (ghost && disabled) { - borderColor = 'disabled'; - } else if (checked) { - borderColor = 'primary200'; - } - - const { paddingHorizontal, paddingVertical } = getBySize(size); - if (selectable) return ( - {renderContent()} + {Content} - {renderClosableIcon()} - {renderCheckedIcon()} + {ClosableIcon} + {CheckedIcon} ); return ( - {renderContent()} - {renderClosableIcon()} - {renderCheckedIcon()} + {Content} + {ClosableIcon} + {CheckedIcon} ); }; diff --git a/packages/react-native/src/text/index.tsx b/packages/react-native/src/text/index.tsx index e86c11a5c2..fa449e0689 100644 --- a/packages/react-native/src/text/index.tsx +++ b/packages/react-native/src/text/index.tsx @@ -1,5 +1,7 @@ -import React, { createElement, memo, PropsWithChildren } from 'react'; +import React, { memo, PropsWithChildren } from 'react'; import { TextProps as RNTextProps } from 'react-native'; +// @ts-ignore +import { NativeText } from 'react-native/Libraries/Text/TextNativeComponent'; import { createText, TextProps } from '@shopify/restyle'; @@ -7,9 +9,6 @@ import { Theme } from '../theme'; type Props = TextProps & Omit; -const NativeText = ({ onLongPress, onPress, onPressIn, onPressOut, ...props }: RNTextProps) => - createElement('RCTText', props); - const BaseText = createText(NativeText); const Text = memo(({ children, style, ...props }: PropsWithChildren) => { diff --git a/packages/react-native/src/timeline/HorizontalTimeline.tsx b/packages/react-native/src/timeline/HorizontalTimeline.tsx index 9b4881d348..201ce1c26d 100644 --- a/packages/react-native/src/timeline/HorizontalTimeline.tsx +++ b/packages/react-native/src/timeline/HorizontalTimeline.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { memo } from 'react'; import { LayoutChangeEvent, NativeSyntheticEvent, ScrollView, TextLayoutEventData } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -12,48 +12,23 @@ import { TimelineProps, TimelineStepProps } from './type'; const HorizontalTimeline = ({ data, customIcon, lineStyle }: Omit) => { const [_, { set, get }] = useMap(); + const handleDateLayout = (e: NativeSyntheticEvent, index: number) => { const textWidth = e.nativeEvent.lines[0].width; set(index, Math.floor(textWidth)); }; - const renderDateAndTime = ({ date, time }: TimelineStepProps, index: number) => { - return ( - - handleDateLayout(e, index)}> - {date} - - - {time} - - - ); - }; - - const renderTitleAndDescription = ({ title, description }: TimelineStepProps) => { - return ( - - - {title} - - - {description} - - - ); - }; - const renderItem = (item: TimelineStepProps, index: number) => { return ( - {renderDateAndTime(item, index)} + handleDateLayout(e, index)} /> - {renderTitleAndDescription(item)} + ); }; @@ -68,34 +43,68 @@ HorizontalTimeline.displayName = 'HorizontalTimeline'; export default HorizontalTimeline; -const CircleAndLine = ({ - isLast, - width, - customIcon, - lineStyle, -}: Pick & { isLast: boolean; width: number }) => { - const theme = useTheme(); - const [iconWidth, setIconWidth] = useSafeState(theme.borderRadii.x2); - - const handleLayout = (e: LayoutChangeEvent) => { - setIconWidth(Math.floor(e.nativeEvent.layout.width)); - }; +const DateAndTime = memo( + ({ + date, + time, + onLayout, + }: TimelineStepProps & { onLayout: (event: NativeSyntheticEvent) => void }) => { + return ( + + + {date} + + + {time} + + + ); + } +); +const TitleAndDescription = memo(({ title, description }: TimelineStepProps) => { return ( - - {customIcon ? ( - - {customIcon} - - ) : ( - - )} - {!isLast && } - + + + {title} + + + {description} + + ); -}; +}); + +const CircleAndLine = memo( + ({ + isLast, + width, + customIcon, + lineStyle, + }: Pick & { isLast: boolean; width: number }) => { + const theme = useTheme(); + const [iconWidth, setIconWidth] = useSafeState(theme.borderRadii.x2); + + const handleLayout = (e: LayoutChangeEvent) => { + setIconWidth(Math.floor(e.nativeEvent.layout.width)); + }; + + return ( + + {customIcon ? ( + + {customIcon} + + ) : ( + + )} + {!isLast && } + + ); + } +); diff --git a/packages/react-native/src/timeline/VerticalTimeline.tsx b/packages/react-native/src/timeline/VerticalTimeline.tsx index 2587f998d6..d6a03ec01d 100644 --- a/packages/react-native/src/timeline/VerticalTimeline.tsx +++ b/packages/react-native/src/timeline/VerticalTimeline.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react'; +import React, { memo, useRef } from 'react'; import { LayoutChangeEvent, ScrollView } from 'react-native'; import { useTheme } from '@shopify/restyle'; @@ -26,36 +26,10 @@ const VerticalTimeline = ({ data, customIcon, lineStyle }: Omit { - return ( - - - {date} - - - {time} - - - ); - }; - - const renderEvent = ({ title, description }: TimelineStepProps, index: number) => { - return ( - handleEventLayout(e, index)} flex={1}> - - {title} - - - {description} - - - ); - }; - const renderItem = (item: TimelineStepProps, index: number) => { return ( - {renderDateAndTime(item)} + - {renderEvent(item, index)} + handleEventLayout(e, index)} /> ); }; @@ -78,41 +52,79 @@ VerticalTimeline.displayName = 'VerticalTimeline'; export default VerticalTimeline; -const CircleAndLine = ({ - height, - isLast, - titleHeight, - customIcon, - lineStyle, -}: { height: number; isLast: boolean; titleHeight: number } & Pick) => { - const theme = useTheme(); - const [iconHeight, setIconHeight] = useSafeState(theme.borderRadii.x2); - - const handleLayout = (e: LayoutChangeEvent) => { - setIconHeight(Math.floor(e.nativeEvent.layout.height)); - }; - +const DateAndTime = memo(({ date, time }: TimelineStepProps) => { return ( - - {customIcon ? ( - - {customIcon} - - ) : ( - - )} - {!isLast && } + + + {date} + + + {time} + ); -}; +}); + +const Event = memo( + ({ + title, + description, + onLayout, + onTitleLayout, + }: TimelineStepProps & { + onTitleLayout: (event: LayoutChangeEvent) => void; + onLayout: (event: LayoutChangeEvent) => void; + }) => { + return ( + + + {title} + + + {description} + + + ); + } +); + +const CircleAndLine = memo( + ({ + height, + isLast, + titleHeight, + customIcon, + lineStyle, + }: { height: number; isLast: boolean; titleHeight: number } & Pick) => { + const theme = useTheme(); + const [iconHeight, setIconHeight] = useSafeState(theme.borderRadii.x2); + + const handleLayout = (e: LayoutChangeEvent) => { + setIconHeight(Math.floor(e.nativeEvent.layout.height)); + }; + + return ( + + {customIcon ? ( + + {customIcon} + + ) : ( + + )} + {!isLast && } + + ); + } +); diff --git a/packages/react-native/src/tooltip/Triangle.tsx b/packages/react-native/src/tooltip/Triangle.tsx index 2f714e5a0d..720a901692 100644 --- a/packages/react-native/src/tooltip/Triangle.tsx +++ b/packages/react-native/src/tooltip/Triangle.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { memo } from 'react'; import { StyleProp, StyleSheet, ViewStyle } from 'react-native'; import Box from '../box'; @@ -8,7 +8,9 @@ type Props = { isDown: boolean; }; -const Triangle = ({ style, isDown }: Props) => ; +const Triangle = memo(({ style, isDown }: Props) => ( + +)); const styles = StyleSheet.create({ down: { diff --git a/packages/react-native/src/tooltip/index.tsx b/packages/react-native/src/tooltip/index.tsx index d72237dbe1..bccacde772 100644 --- a/packages/react-native/src/tooltip/index.tsx +++ b/packages/react-native/src/tooltip/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, PropsWithChildren, ReactNode, Reducer, useReducer, useRef } from 'react'; +import React, { FC, memo, PropsWithChildren, ReactNode, Reducer, useMemo, useReducer, useRef } from 'react'; import { Dimensions, LayoutChangeEvent, Modal, Pressable, StyleProp, View, ViewStyle } from 'react-native'; import Box from '../box'; @@ -108,7 +108,7 @@ const Tooltip: FC> = props => { dispatch({ type: 'toggle' }); }; - const getTooltipStyle = () => { + const Content = useMemo(() => { const { x, y } = getTooltipCoordinate( offsetX, offsetY, @@ -141,30 +141,6 @@ const Tooltip: FC> = props => { tooltipStyle.top = y; } - return { tooltipStyle, pastMiddleLine, pastCenterLine }; - }; - - const renderPointer = (pastMiddleLine: boolean, pastCenterLine: boolean) => { - return ( - - - - ); - }; - - const renderContent = () => { - const { pastMiddleLine, pastCenterLine, tooltipStyle } = getTooltipStyle(); return ( <> > = props => { > {children} - {withCaret && renderPointer(pastMiddleLine, pastCenterLine)} + {typeof content === 'string' ? ( @@ -191,7 +178,7 @@ const Tooltip: FC> = props => { ); - }; + }, [offsetX, offsetY, elementWidth, elementHeight, ScreenWidth, ScreenHeight, width, withCaret, backgroundColor]); const pressableProps = { [actionType]: toggleTooltip, @@ -212,7 +199,7 @@ const Tooltip: FC> = props => { }} onPress={toggleTooltip} > - {renderContent()} + {Content} @@ -220,3 +207,44 @@ const Tooltip: FC> = props => { }; export default Tooltip; + +const Pointer = memo( + ({ + withCaret, + pastCenterLine, + pastMiddleLine, + offsetY, + offsetX, + elementHeight, + elementWidth, + backgroundColor, + }: { + withCaret: boolean; + pastMiddleLine: boolean; + pastCenterLine: boolean; + offsetY: number; + offsetX: number; + elementHeight: number; + elementWidth: number; + backgroundColor: string; + }) => { + if (!withCaret) return null; + + return ( + + + + ); + } +); diff --git a/packages/react-native/src/tree/Checkbox.tsx b/packages/react-native/src/tree/Checkbox.tsx index f15b8b7f36..20fcaf72cb 100644 --- a/packages/react-native/src/tree/Checkbox.tsx +++ b/packages/react-native/src/tree/Checkbox.tsx @@ -1,11 +1,11 @@ -import React from 'react'; +import React, { memo } from 'react'; import { SvgXml } from 'react-native-svg'; import { useTheme } from '@shopify/restyle'; import { Theme } from '../theme'; -export default function Checkbox({ disabled, checked }: { disabled?: boolean; checked: 'all' | 'half' | 'none' }) { +const Checkbox = memo(({ disabled, checked }: { disabled?: boolean; checked: 'all' | 'half' | 'none' }) => { const theme = useTheme(); if (checked === 'all') { @@ -29,4 +29,6 @@ export default function Checkbox({ disabled, checked }: { disabled?: boolean; ch xml={``} /> ); -} +}); + +export default Checkbox; diff --git a/packages/react-native/src/tree/Chevron.tsx b/packages/react-native/src/tree/Chevron.tsx index 9adfbd2d1d..d42a620d2b 100644 --- a/packages/react-native/src/tree/Chevron.tsx +++ b/packages/react-native/src/tree/Chevron.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import Animated, { useAnimatedStyle } from 'react-native-reanimated'; import { mix } from 'react-native-redash'; @@ -20,4 +20,4 @@ const Chevron: FC<{ progress: Animated.SharedValue }> = ({ progress }) = ); }; -export default Chevron; +export default memo(Chevron); diff --git a/packages/react-native/src/tree/TreeGroup.tsx b/packages/react-native/src/tree/TreeGroup.tsx index ed39bb07c5..dfdac1f4cc 100644 --- a/packages/react-native/src/tree/TreeGroup.tsx +++ b/packages/react-native/src/tree/TreeGroup.tsx @@ -1,4 +1,4 @@ -import { PropsWithChildren } from 'react'; +import { memo, PropsWithChildren } from 'react'; import React from 'react'; import Animated from 'react-native-reanimated'; @@ -15,7 +15,7 @@ import { TreeItemProps, TreeProps } from './type'; import useGroup from './useGroup'; import { useTree } from './useTree'; -export default function TreeGroup({ +function TreeGroup({ id, text, disabled, @@ -80,3 +80,5 @@ export default function TreeGroup({ ); } + +export default memo(TreeGroup); diff --git a/packages/react-native/src/tree/useGroup.ts b/packages/react-native/src/tree/useGroup.ts index 4584589ba1..f9b0ebe816 100644 --- a/packages/react-native/src/tree/useGroup.ts +++ b/packages/react-native/src/tree/useGroup.ts @@ -76,7 +76,7 @@ export default function useGroup({ progress, checkStatus, - handleLayout: useMemoizedFn(handleLayout), + handleLayout, handlePress: useMemoizedFn(handlePress), }; } diff --git a/packages/react-native/src/white-space/index.tsx b/packages/react-native/src/white-space/index.tsx index a4e515f4ba..5820530cf7 100644 --- a/packages/react-native/src/white-space/index.tsx +++ b/packages/react-native/src/white-space/index.tsx @@ -1,4 +1,4 @@ -import React, { FC } from 'react'; +import React, { FC, memo } from 'react'; import { useTheme } from '@shopify/restyle'; @@ -16,4 +16,4 @@ const WhiteSpace: FC = ({ size = 'x2', backgroundColor = 'trans }; WhiteSpace.displayName = 'WhiteSpace'; -export default WhiteSpace; +export default memo(WhiteSpace); diff --git a/packages/react-native/src/wing-blank/index.tsx b/packages/react-native/src/wing-blank/index.tsx index cfb8856ae8..6f27fb466b 100644 --- a/packages/react-native/src/wing-blank/index.tsx +++ b/packages/react-native/src/wing-blank/index.tsx @@ -1,4 +1,4 @@ -import React, { FC, PropsWithChildren } from 'react'; +import React, { FC, memo, PropsWithChildren } from 'react'; import { BoxProps } from '@shopify/restyle'; @@ -18,4 +18,4 @@ const WingBlank: FC> = ({ children, size = 'x2 }; WingBlank.displayName = 'WingBlank'; -export default WingBlank; +export default memo(WingBlank); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7933009c53..dda8979ce0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,5 +1,8 @@ lockfileVersion: 5.4 +overrides: + '@types/react': 17.0.43 + importers: .: @@ -117,7 +120,7 @@ importers: '@rollup/plugin-node-resolve': ^15.1.0 '@types/lodash-es': ^4.17.8 '@types/node': ^20.4.4 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 lodash-es: ^4.17.21 rollup: ^3.26.3 @@ -132,7 +135,7 @@ importers: '@rollup/plugin-node-resolve': 15.1.0_rollup@3.26.3 '@types/lodash-es': 4.17.8 '@types/node': 20.4.4 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 rollup: 3.26.3 rollup-plugin-typescript2: 0.35.0_afuk5ckrta3fepxfxriis2nsxm @@ -148,7 +151,7 @@ importers: '@rollup/plugin-node-resolve': ^15.1.0 '@types/color': ^3.0.3 '@types/lodash-es': ^4.17.8 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-dom': ^18.2.7 classnames: ^2.3.2 color: ^4.2.3 @@ -188,7 +191,7 @@ importers: '@rollup/plugin-node-resolve': 15.1.0_rollup@3.26.3 '@types/color': 3.0.3 '@types/lodash-es': 4.17.8 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-dom': 18.2.7 less: 4.1.3 postcss: 8.4.27 @@ -206,7 +209,7 @@ importers: '@rollup/plugin-commonjs': ^25.0.3 '@rollup/plugin-node-resolve': ^15.1.0 '@types/lodash-es': ^4.17.8 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-dom': ^18.2.7 echarts: ^5.4.3 echarts-for-react: ^3.0.2 @@ -228,7 +231,7 @@ importers: '@rollup/plugin-commonjs': 25.0.3_rollup@3.26.3 '@rollup/plugin-node-resolve': 15.1.0_rollup@3.26.3 '@types/lodash-es': 4.17.8 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-dom': 18.2.7 less: 4.1.3 postcss: 8.4.27 @@ -245,7 +248,7 @@ importers: '@rollup/plugin-commonjs': ^25.0.3 '@rollup/plugin-node-resolve': ^15.1.0 '@types/lodash-es': ^4.17.8 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-dom': ^18.2.7 lodash-es: ^4.17.21 rollup: ^3.26.3 @@ -261,7 +264,7 @@ importers: '@rollup/plugin-commonjs': 25.0.3_rollup@3.26.3 '@rollup/plugin-node-resolve': 15.1.0_rollup@3.26.3 '@types/lodash-es': 4.17.8 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-dom': 18.2.7 rollup: 3.26.3 rollup-plugin-typescript2: 0.35.0_afuk5ckrta3fepxfxriis2nsxm @@ -272,7 +275,7 @@ importers: specifiers: '@shopify/restyle': 2.4.2 '@td-design/rn-hooks': ^2.7.3 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 rc-field-form: ^1.34.2 react-native-builder-bob: ^0.21.3 @@ -289,7 +292,7 @@ importers: rc-field-form: 1.34.2 react-native-shadow-2: 7.0.8_react-native-svg@13.10.0 devDependencies: - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-gesture-handler: 2.12.0 @@ -301,21 +304,21 @@ importers: packages/react-native-alipay: specifiers: - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 devDependencies: - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 packages/react-native-amap-search: specifiers: - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 pod-install: ^0.1.38 react-native-builder-bob: ^0.21.3 typescript: ^5.1.6 devDependencies: - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 pod-install: 0.1.38 react-native-builder-bob: 0.21.3 @@ -327,7 +330,7 @@ importers: '@td-design/react-native': workspace:^5.3.0 '@td-design/react-native-picker': workspace:^2.3.2 '@td-design/rn-hooks': workspace:^2.7.2 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 dayjs: ^1.11.9 react-native-builder-bob: ^0.21.3 @@ -343,7 +346,7 @@ importers: '@td-design/react-native': link:../react-native '@td-design/react-native-picker': link:../react-native-picker '@td-design/rn-hooks': link:../hooks - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-gesture-handler: 2.12.0 @@ -354,13 +357,13 @@ importers: packages/react-native-echarts: specifiers: - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 react-native-builder-bob: ^0.21.3 react-native-webview: ^13.2.3 typescript: ^5.1.6 devDependencies: - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-webview: 13.2.3 @@ -371,7 +374,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': workspace:^5.3.0 '@td-design/rn-hooks': workspace:^2.7.2 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: ^0.21.3 react-native-image-picker: ^5.6.0 @@ -380,7 +383,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': link:../react-native '@td-design/rn-hooks': link:../hooks - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-image-picker: 5.6.0 @@ -391,7 +394,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': workspace:^5.3.0 '@td-design/rn-hooks': workspace:^2.7.2 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 react-native-builder-bob: ^0.21.3 typescript: ^5.1.6 @@ -399,7 +402,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': link:../react-native '@td-design/rn-hooks': link:../hooks - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 typescript: 5.1.6 @@ -410,7 +413,7 @@ importers: '@td-design/react-native': workspace:^5.3.0 '@td-design/rn-hooks': workspace:^2.7.2 '@types/lodash-es': ^4.17.8 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 array-tree-filter: ^2.1.0 dayjs: ^1.11.9 @@ -428,7 +431,7 @@ importers: '@td-design/react-native': link:../react-native '@td-design/rn-hooks': link:../hooks '@types/lodash-es': 4.17.8 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 typescript: 5.1.6 @@ -438,7 +441,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': workspace:^5.3.0 '@td-design/rn-hooks': workspace:^2.7.2 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 react-native-builder-bob: ^0.21.3 react-native-gesture-handler: ^2.12.0 @@ -450,7 +453,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': link:../react-native '@td-design/rn-hooks': link:../hooks - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-gesture-handler: 2.12.0 @@ -463,7 +466,7 @@ importers: specifiers: '@shopify/restyle': 2.4.2 '@td-design/react-native': workspace:^5.3.0 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 react-native-builder-bob: ^0.21.3 react-native-svg: ^13.10.0 @@ -471,7 +474,7 @@ importers: devDependencies: '@shopify/restyle': 2.4.2 '@td-design/react-native': link:../react-native - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-svg: 13.10.0 @@ -482,7 +485,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': workspace:^5.3.0 '@td-design/rn-hooks': workspace:^2.7.2 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 react-native-builder-bob: ^0.21.3 react-native-linear-gradient: ^2.8.0 @@ -492,7 +495,7 @@ importers: '@shopify/restyle': 2.4.2 '@td-design/react-native': link:../react-native '@td-design/rn-hooks': link:../hooks - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-linear-gradient: 2.8.0 @@ -503,7 +506,7 @@ importers: specifiers: '@td-design/react-native': workspace:^5.3.0 '@td-design/rn-hooks': workspace:^2.7.2 - '@types/react': ^18.2.15 + '@types/react': 17.0.43 '@types/react-native': ^0.72.2 color: ^4.2.3 react-native-builder-bob: ^0.21.3 @@ -515,7 +518,7 @@ importers: devDependencies: '@td-design/react-native': link:../react-native '@td-design/rn-hooks': link:../hooks - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-native': 0.72.2 react-native-builder-bob: 0.21.3 react-native-pager-view: 6.2.0 @@ -3373,20 +3376,20 @@ packages: /@types/react-dom/16.9.19: resolution: {integrity: sha512-xC8D280Bf6p0zguJ8g62jcEOKZiUbx9sIe6O3tT/lKfR87A7A6g65q13z6D5QUMIa/6yFPkNhqjF5z/VVZEYqQ==} dependencies: - '@types/react': 16.14.43 + '@types/react': 17.0.43 dev: true /@types/react-dom/18.2.7: resolution: {integrity: sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==} dependencies: - '@types/react': 18.2.15 + '@types/react': 17.0.43 dev: true /@types/react-native/0.72.2: resolution: {integrity: sha512-/eEjr04Zqo7mTMszuSdrLx90+j5nWhDMMOgtnKZfAYyV3RwmlpSb7F17ilmMMxZWJY81n/JZ4e6wdhMJFpjrCg==} dependencies: '@react-native/virtualized-lists': 0.72.6 - '@types/react': 18.2.15 + '@types/react': 17.0.43 transitivePeerDependencies: - react-native dev: true @@ -3395,7 +3398,7 @@ packages: resolution: {integrity: sha512-WOSetDV3YPxbkVJAdv/bqExJjmcdCi/vpCJh3NfQOy1X15vHMSiMioXIcGekXDJJYhqGUMDo9e337mh508foAA==} dependencies: '@types/history': 5.0.0 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-router': 5.1.20 dev: true @@ -3403,7 +3406,7 @@ packages: resolution: {integrity: sha512-pFFVXUIydHlcJP6wJm7sDii5mD/bCmmAY0wQzq+M+uX7bqS95AQqHZWP1iNMKrWVQSuHIzj5qi9BvrtLX2/T4w==} dependencies: '@types/history': 4.7.11 - '@types/react': 16.14.43 + '@types/react': 17.0.43 '@types/react-router': 5.1.20 dev: true @@ -3411,7 +3414,7 @@ packages: resolution: {integrity: sha512-D5mHD6TbdV/DNHYsnwBTv+y73ei+mMjrkGrla86HthE4/PVvL1J94Bu3qABU+COXzpL23T1EZapVVpwHuBXiUg==} dependencies: '@types/history': 5.0.0 - '@types/react': 18.2.15 + '@types/react': 17.0.43 '@types/react-router': 5.1.12 dev: true @@ -3419,26 +3422,18 @@ packages: resolution: {integrity: sha512-0bhXQwHYfMeJlCh7mGhc0VJTRm0Gk+Z8T00aiP4702mDUuLs9SMhnd2DitpjWFjdOecx2UXtICK14H9iMnziGA==} dependencies: '@types/history': 5.0.0 - '@types/react': 18.2.15 + '@types/react': 17.0.43 dev: true /@types/react-router/5.1.20: resolution: {integrity: sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==} dependencies: '@types/history': 4.7.11 - '@types/react': 18.2.15 - dev: true - - /@types/react/16.14.43: - resolution: {integrity: sha512-7zdjv7jvoLLQg1tTvpQsm+hyNUMT2mPlNV1+d0I8fbGhkJl82spopMyBlu4wb1dviZAxpGdk5eHu/muacknnfw==} - dependencies: - '@types/prop-types': 15.7.5 - '@types/scheduler': 0.16.3 - csstype: 3.1.2 + '@types/react': 17.0.43 dev: true - /@types/react/18.2.15: - resolution: {integrity: sha512-oEjE7TQt1fFTFSbf8kkNuc798ahTUzn3Le67/PWjE8MAfYAD/qB7O8hSTcromLFqHCt9bcdOg5GXMokzTjJ5SA==} + /@types/react/17.0.43: + resolution: {integrity: sha512-8Q+LNpdxf057brvPu1lMtC5Vn7J119xrP1aq4qiaefNioQUYANF/CYeK4NsKorSZyUGJ66g0IM+4bbjwx45o2A==} dependencies: '@types/prop-types': 15.7.5 '@types/scheduler': 0.16.3 @@ -3769,7 +3764,7 @@ packages: react: 16.x || 17.x react-dom: 16.x || 17.x dependencies: - '@types/react': 16.14.43 + '@types/react': 17.0.43 '@types/react-dom': 16.9.19 '@umijs/runtime': 3.5.41_react@16.14.0 react: 16.14.0 @@ -3782,7 +3777,7 @@ packages: react: 16.x || 17.x react-dom: 16.x || 17.x dependencies: - '@types/react': 16.14.43 + '@types/react': 17.0.43 '@types/react-dom': 16.9.19 '@types/react-router-config': 5.0.7 '@umijs/runtime': 3.5.41_react@16.14.0 @@ -3799,7 +3794,7 @@ packages: react: 16.x || 17.x react-dom: 16.x || 17.x dependencies: - '@types/react': 16.14.43 + '@types/react': 17.0.43 '@types/react-dom': 16.9.19 '@types/react-router-config': 5.0.7 '@umijs/runtime': 3.5.41_react@17.0.2 @@ -3815,7 +3810,7 @@ packages: react: 16.x || 17.x react-dom: 16.x || 17.x dependencies: - '@types/react': 16.14.43 + '@types/react': 17.0.43 '@types/react-dom': 16.9.19 '@types/react-router-config': 5.0.7 '@umijs/runtime': 3.5.41_react@16.14.0 From dc908cf2c920a88f8a50e980a7cd88279467315d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E6=9D=B0?= Date: Tue, 10 Oct 2023 10:31:21 +0800 Subject: [PATCH 2/2] =?UTF-8?q?perf:=20=E5=AF=B9=E7=BB=84=E4=BB=B6?= =?UTF-8?q?=E5=BA=93=E7=BB=84=E4=BB=B6=E8=BF=9B=E8=A1=8C=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .changeset/swift-kids-matter.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/swift-kids-matter.md diff --git a/.changeset/swift-kids-matter.md b/.changeset/swift-kids-matter.md new file mode 100644 index 0000000000..f664970f3d --- /dev/null +++ b/.changeset/swift-kids-matter.md @@ -0,0 +1,5 @@ +--- +'@td-design/react-native': minor +--- + +对组件库组件进行优化