Browse Source

🦄️ refactor: use React.useMemo replace function (#41550)

* 🦄️ refactor: use React.useMemo replace function

* add

* fix

* add

* add
pull/41556/head
lijianan 2 years ago
committed by GitHub
parent
commit
65224d357d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 19
      components/cascader/index.tsx
  2. 42
      components/collapse/Collapse.tsx
  3. 31
      components/drawer/DrawerPanel.tsx
  4. 73
      components/dropdown/dropdown.tsx
  5. 23
      components/mentions/index.tsx
  6. 9
      components/select/index.tsx
  7. 23
      components/tree-select/index.tsx

19
components/cascader/index.tsx

@ -7,30 +7,31 @@ import type {
DefaultOptionType,
FieldNames,
MultipleCascaderProps as RcMultipleCascaderProps,
ShowSearchType,
SingleCascaderProps as RcSingleCascaderProps,
ShowSearchType,
} from 'rc-cascader';
import RcCascader from 'rc-cascader';
import type { Placement } from 'rc-select/lib/BaseSelect';
import omit from 'rc-util/lib/omit';
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import DisabledContext from '../config-provider/DisabledContext';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import { useCompactItemContext } from '../space/Compact';
import { FormItemInputContext } from '../form/context';
import getIcons from '../select/utils/iconUtil';
import type { SelectCommonPlacement } from '../_util/motion';
import { getTransitionDirection, getTransitionName } from '../_util/motion';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import warning from '../_util/warning';
import { FormItemInputContext } from '../form/context';
import getIcons from '../select/utils/iconUtil';
import genPurePanel from '../_util/PurePanel';
import useSelectStyle from '../select/style';
import useShowArrow from '../select/useShowArrow';
import genPurePanel from '../_util/PurePanel';
import useStyle from './style';
// Align the design since we use `rc-select` in root. This help:
@ -85,7 +86,7 @@ const defaultSearchRender: ShowSearchType['render'] = (inputValue, path, prefixC
optionList.push(' / ');
}
let label = (node as any)[fieldNames.label!];
let label = node[fieldNames.label!];
const type = typeof label;
if (type === 'string' || type === 'number') {
label = highlightKeyword(String(label), lower, prefixCls);
@ -266,12 +267,12 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
});
// ===================== Placement =====================
const getPlacement = () => {
const memoPlacement = React.useMemo<Placement>(() => {
if (placement !== undefined) {
return placement;
}
return isRtl ? 'bottomRight' : 'bottomLeft';
};
}, [placement, isRtl]);
// ==================== Render =====================
const renderNode = (
@ -295,7 +296,7 @@ const Cascader = React.forwardRef((props: CascaderProps<any>, ref: React.Ref<Cas
disabled={mergedDisabled}
{...(restProps as any)}
direction={mergedDirection}
placement={getPlacement()}
placement={memoPlacement}
notFoundContent={mergedNotFoundContent}
allowClear={allowClear}
showSearch={mergedShowSearch}

42
components/collapse/Collapse.tsx

@ -6,13 +6,13 @@ import * as React from 'react';
import toArray from 'rc-util/lib/Children/toArray';
import omit from 'rc-util/lib/omit';
import { ConfigContext } from '../config-provider';
import initCollapseMotion from '../_util/motion';
import { cloneElement } from '../_util/reactNode';
import warning from '../_util/warning';
import type { CollapsibleType } from './CollapsePanel';
import { ConfigContext } from '../config-provider';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import type { CollapsibleType } from './CollapsePanel';
import CollapsePanel from './CollapsePanel';
import useStyle from './style';
@ -66,6 +66,8 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
ghost,
size: customizeSize,
expandIconPosition = 'start',
children,
expandIcon,
} = props;
const mergedSize = customizeSize || size || 'middle';
@ -89,7 +91,6 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
}, [expandIconPosition]);
const renderExpandIcon = (panelProps: PanelProps = {}) => {
const { expandIcon } = props;
const icon = (
expandIcon ? (
expandIcon(panelProps)
@ -121,22 +122,23 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
leavedClassName: `${prefixCls}-content-hidden`,
};
const getItems = () => {
const { children } = props;
return toArray(children).map((child: React.ReactElement, index: number) => {
if (child.props?.disabled) {
const key = child.key || String(index);
const { disabled, collapsible } = child.props;
const childProps: CollapseProps & { key: React.Key } = {
...omit(child.props, ['disabled']),
key,
collapsible: collapsible ?? (disabled ? 'disabled' : undefined),
};
return cloneElement(child, childProps);
}
return child;
});
};
const items = React.useMemo<React.ReactNode[]>(
() =>
toArray(children).map<React.ReactNode>((child, index) => {
if (child.props?.disabled) {
const key = child.key ?? String(index);
const { disabled, collapsible } = child.props;
const childProps: CollapseProps & { key: React.Key } = {
...omit(child.props, ['disabled']),
key,
collapsible: collapsible ?? (disabled ? 'disabled' : undefined),
};
return cloneElement(child, childProps);
}
return child;
}),
[children],
);
return wrapSSR(
<RcCollapse
@ -147,7 +149,7 @@ const Collapse = React.forwardRef<HTMLDivElement, CollapseProps>((props, ref) =>
prefixCls={prefixCls}
className={collapseClassName}
>
{getItems()}
{items}
</RcCollapse>,
);
});

31
components/drawer/DrawerPanel.tsx

@ -1,7 +1,7 @@
import * as React from 'react';
import CloseOutlined from '@ant-design/icons/CloseOutlined';
import type { DrawerProps as RCDrawerProps } from 'rc-drawer';
import classNames from 'classnames';
import type { DrawerProps as RCDrawerProps } from 'rc-drawer';
import * as React from 'react';
export interface DrawerPanelProps {
prefixCls: string;
@ -22,18 +22,15 @@ export interface DrawerPanelProps {
children?: React.ReactNode;
}
export default function DrawerPanel(props: DrawerPanelProps) {
const DrawerPanel: React.FC<DrawerPanelProps> = (props) => {
const {
prefixCls,
title,
footer,
extra,
closable = true,
closeIcon = <CloseOutlined />,
onClose,
headerStyle,
drawerStyle,
bodyStyle,
@ -47,17 +44,16 @@ export default function DrawerPanel(props: DrawerPanelProps) {
</button>
);
function renderHeader() {
const headerNode = React.useMemo<React.ReactNode>(() => {
if (!title && !closable) {
return null;
}
return (
<div
style={headerStyle}
className={classNames(`${prefixCls}-header`, {
[`${prefixCls}-header-close-only`]: closable && !title && !extra,
})}
style={headerStyle}
>
<div className={`${prefixCls}-header-title`}>
{closeIconNode}
@ -66,28 +62,29 @@ export default function DrawerPanel(props: DrawerPanelProps) {
{extra && <div className={`${prefixCls}-extra`}>{extra}</div>}
</div>
);
}
}, [closable, closeIconNode, extra, headerStyle, prefixCls, title]);
function renderFooter() {
const footerNode = React.useMemo<React.ReactNode>(() => {
if (!footer) {
return null;
}
const footerClassName = `${prefixCls}-footer`;
return (
<div className={footerClassName} style={footerStyle}>
{footer}
</div>
);
}
}, [footer, footerStyle, prefixCls]);
return (
<div className={`${prefixCls}-wrapper-body`} style={{ ...drawerStyle }}>
{renderHeader()}
<div className={`${prefixCls}-wrapper-body`} style={drawerStyle}>
{headerNode}
<div className={`${prefixCls}-body`} style={bodyStyle}>
{children}
</div>
{renderFooter()}
{footerNode}
</div>
);
}
};
export default DrawerPanel;

73
components/dropdown/dropdown.tsx

@ -5,19 +5,19 @@ import useEvent from 'rc-util/lib/hooks/useEvent';
import useMergedState from 'rc-util/lib/hooks/useMergedState';
import omit from 'rc-util/lib/omit';
import * as React from 'react';
import genPurePanel from '../_util/PurePanel';
import type { AdjustOverflow } from '../_util/placements';
import getPlacements from '../_util/placements';
import { cloneElement } from '../_util/reactNode';
import warning from '../_util/warning';
import { ConfigContext } from '../config-provider';
import type { MenuProps } from '../menu';
import Menu from '../menu';
import { OverrideProvider } from '../menu/OverrideContext';
import { NoCompactStyle } from '../space/Compact';
import type { AdjustOverflow } from '../_util/placements';
import getPlacements from '../_util/placements';
import genPurePanel from '../_util/PurePanel';
import { cloneElement } from '../_util/reactNode';
import warning from '../_util/warning';
import theme from '../theme';
import DropdownButton from './dropdown-button';
import useStyle from './style';
import theme from '../theme';
const Placements = [
'topLeft',
@ -92,6 +92,29 @@ type CompoundedComponent = React.FC<DropdownProps> & {
};
const Dropdown: CompoundedComponent = (props) => {
const {
menu,
arrow,
prefixCls: customizePrefixCls,
children,
trigger,
disabled,
dropdownRender,
getPopupContainer,
overlayClassName,
rootClassName,
open,
onOpenChange,
// Deprecated
visible,
onVisibleChange,
mouseEnterDelay = 0.15,
mouseLeaveDelay = 0.1,
autoAdjustOverflow = true,
placement = '',
overlay,
transitionName,
} = props;
const {
getPopupContainer: getContextPopupContainer,
getPrefixCls,
@ -118,9 +141,9 @@ const Dropdown: CompoundedComponent = (props) => {
);
}
const getTransitionName = () => {
const memoTransitionName = React.useMemo<string>(() => {
const rootPrefixCls = getPrefixCls();
const { placement = '', transitionName } = props;
if (transitionName !== undefined) {
return transitionName;
}
@ -128,10 +151,9 @@ const Dropdown: CompoundedComponent = (props) => {
return `${rootPrefixCls}-slide-down`;
}
return `${rootPrefixCls}-slide-up`;
};
}, [getPrefixCls, placement, transitionName]);
const getPlacement = () => {
const { placement } = props;
const memoPlacement = React.useMemo<string>(() => {
if (!placement) {
return direction === 'rtl' ? 'bottomRight' : 'bottomLeft';
}
@ -147,29 +169,7 @@ const Dropdown: CompoundedComponent = (props) => {
}
return placement;
};
const {
menu,
arrow,
prefixCls: customizePrefixCls,
children,
trigger,
disabled,
dropdownRender,
getPopupContainer,
overlayClassName,
rootClassName,
open,
onOpenChange,
// Deprecated
visible,
onVisibleChange,
mouseEnterDelay = 0.15,
mouseLeaveDelay = 0.1,
autoAdjustOverflow = true,
} = props;
}, [placement, direction]);
if (process.env.NODE_ENV !== 'production') {
[
@ -239,7 +239,6 @@ const Dropdown: CompoundedComponent = (props) => {
const renderOverlay = () => {
// rc-dropdown already can process the function of overlay, but we have check logic here.
// So we need render the element to check and pass back to rc-dropdown.
const { overlay } = props;
let overlayNode: React.ReactNode;
if (menu?.items) {
@ -294,10 +293,10 @@ const Dropdown: CompoundedComponent = (props) => {
overlayClassName={overlayClassNameCustomized}
prefixCls={prefixCls}
getPopupContainer={getPopupContainer || getContextPopupContainer}
transitionName={getTransitionName()}
transitionName={memoTransitionName}
trigger={triggerActions}
overlay={renderOverlay}
placement={getPlacement()}
placement={memoPlacement}
onVisibleChange={onInnerOpenChange}
>
{dropdownTrigger}

23
components/mentions/index.tsx

@ -8,14 +8,14 @@ import type {
import { composeRef } from 'rc-util/lib/ref';
// eslint-disable-next-line import/no-named-as-default
import * as React from 'react';
import { ConfigContext } from '../config-provider';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import { FormItemInputContext } from '../form/context';
import Spin from '../spin';
import genPurePanel from '../_util/PurePanel';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import warning from '../_util/warning';
import { ConfigContext } from '../config-provider';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import { FormItemInputContext } from '../form/context';
import Spin from '../spin';
import useStyle from './style';
@ -81,7 +81,7 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
ref,
) => {
const [focused, setFocused] = React.useState(false);
const innerRef = React.useRef<MentionsRef>();
const innerRef = React.useRef<MentionsRef>(null);
const mergedRef = composeRef(ref, innerRef);
// =================== Warning =====================
@ -123,7 +123,7 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
return renderEmpty?.('Select') || <DefaultRenderEmpty componentName="Select" />;
}, [notFoundContent, renderEmpty]);
const getOptions = () => {
const mentionOptions = React.useMemo<React.ReactNode>(() => {
if (loading) {
return (
<Option value="ANTD_SEARCHING" disabled>
@ -131,9 +131,8 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
</Option>
);
}
return children;
};
}, [loading, children]);
const mergedOptions = loading
? [
@ -176,14 +175,12 @@ const InternalMentions: React.ForwardRefRenderFunction<MentionsRef, MentionProps
onFocus={onFocus}
onBlur={onBlur}
dropdownClassName={classNames(popupClassName, rootClassName, hashId)}
ref={mergedRef as any}
ref={mergedRef}
options={mergedOptions}
suffix={hasFeedback && feedbackIcon}
classes={{
affixWrapper: classNames(hashId, className),
}}
classes={{ affixWrapper: classNames(hashId, className) }}
>
{getOptions()}
{mentionOptions}
</RcMentions>
);

9
components/select/index.tsx

@ -6,23 +6,22 @@ import type { OptionProps } from 'rc-select/lib/Option';
import type { BaseOptionType, DefaultOptionType } from 'rc-select/lib/Select';
import omit from 'rc-util/lib/omit';
import * as React from 'react';
import genPurePanel from '../_util/PurePanel';
import type { SelectCommonPlacement } from '../_util/motion';
import { getTransitionDirection, getTransitionName } from '../_util/motion';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import warning from '../_util/warning';
import { ConfigContext } from '../config-provider';
import DisabledContext from '../config-provider/DisabledContext';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import { FormItemInputContext } from '../form/context';
import getIcons from './utils/iconUtil';
import genPurePanel from '../_util/PurePanel';
import warning from '../_util/warning';
import { useCompactItemContext } from '../space/Compact';
import useStyle from './style';
import useShowArrow from './useShowArrow';
import getIcons from './utils/iconUtil';
type RawValue = string | number;
@ -201,7 +200,7 @@ const InternalSelect = <OptionType extends BaseOptionType | DefaultOptionType =
// ====================== Render =======================
return wrapSSR(
<RcSelect<any, any>
ref={ref as any}
ref={ref}
virtual={virtual}
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
showSearch={select?.showSearch}

23
components/tree-select/index.tsx

@ -1,32 +1,31 @@
import classNames from 'classnames';
import type { BaseSelectRef } from 'rc-select';
import type { Placement } from 'rc-select/lib/BaseSelect';
import type { TreeSelectProps as RcTreeSelectProps } from 'rc-tree-select';
import RcTreeSelect, { SHOW_ALL, SHOW_CHILD, SHOW_PARENT, TreeNode } from 'rc-tree-select';
import type { BaseOptionType, DefaultOptionType } from 'rc-tree-select/lib/TreeSelect';
import omit from 'rc-util/lib/omit';
import * as React from 'react';
import type { Placement } from 'rc-select/lib/BaseSelect';
import genPurePanel from '../_util/PurePanel';
import type { SelectCommonPlacement } from '../_util/motion';
import { getTransitionDirection, getTransitionName } from '../_util/motion';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import warning from '../_util/warning';
import { ConfigContext } from '../config-provider';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import DisabledContext from '../config-provider/DisabledContext';
import type { SizeType } from '../config-provider/SizeContext';
import SizeContext from '../config-provider/SizeContext';
import DefaultRenderEmpty from '../config-provider/defaultRenderEmpty';
import { FormItemInputContext } from '../form/context';
import genPurePanel from '../_util/PurePanel';
import useSelectStyle from '../select/style';
import useShowArrow from '../select/useShowArrow';
import getIcons from '../select/utils/iconUtil';
import { useCompactItemContext } from '../space/Compact';
import type { AntTreeNodeProps, TreeProps } from '../tree';
import type { SwitcherIcon } from '../tree/Tree';
import renderSwitcherIcon from '../tree/utils/iconUtil';
import type { SelectCommonPlacement } from '../_util/motion';
import { getTransitionDirection, getTransitionName } from '../_util/motion';
import type { InputStatus } from '../_util/statusUtils';
import { getMergedStatus, getStatusClassNames } from '../_util/statusUtils';
import { useCompactItemContext } from '../space/Compact';
import warning from '../_util/warning';
import useStyle from './style';
import useShowArrow from '../select/useShowArrow';
type RawValue = string | number;
@ -215,7 +214,7 @@ const InternalTreeSelect = <
dropdownMatchSelectWidth={dropdownMatchSelectWidth}
disabled={mergedDisabled}
{...selectProps}
ref={ref as any}
ref={ref}
prefixCls={prefixCls}
className={mergedClassName}
listHeight={listHeight}

Loading…
Cancel
Save