Browse Source

修复IconPicker为空的时候,会无限刷新组件

main
dark 5 months ago
parent
commit
b74edf100c
  1. 11
      src/components/icon/action/ActionIcon.tsx
  2. 10
      src/components/icon/picker/context.tsx
  3. 24
      src/components/icon/picker/index.tsx
  4. 5
      src/pages/system/menus/index.tsx

11
src/components/icon/action/ActionIcon.tsx

@ -1,6 +1,6 @@
import type { ButtonProps, TooltipProps } from 'antd' import type { ButtonProps, TooltipProps } from 'antd'
import { Button, Tooltip } from 'antd' import { Button, Tooltip } from 'antd'
import type { CSSProperties, FC } from 'react'
import { CSSProperties, FC, memo } from 'react'
import { ConfigProvider } from '@/components/config-provider' import { ConfigProvider } from '@/components/config-provider'
import { useStyles } from './style' import { useStyles } from './style'
@ -47,7 +47,7 @@ export interface ActionIconProps extends Omit<ButtonProps, 'title' | 'size'> {
bordered?: boolean; bordered?: boolean;
} }
const BaseActionIcon: FC<ActionIconProps> = ({
const BaseActionIcon: FC<ActionIconProps> = memo(({
placement, placement,
title, title,
icon, icon,
@ -91,9 +91,9 @@ const BaseActionIcon: FC<ActionIconProps> = ({
)} )}
</> </>
) )
}
})
const ActionIcon = (props: ActionIconProps) => {
const ActionIcon = memo((props: ActionIconProps) => {
const { size } = props || {} const { size } = props || {}
const { theme: token } = useStyles({ size }) const { theme: token } = useStyles({ size })
@ -110,5 +110,6 @@ const ActionIcon = (props: ActionIconProps) => {
<BaseActionIcon {...props} /> <BaseActionIcon {...props} />
</ConfigProvider> </ConfigProvider>
) )
}
})
export default ActionIcon export default ActionIcon

10
src/components/icon/picker/context.tsx

@ -2,11 +2,13 @@ import { IconUnit, ReactIcon } from '../types.ts'
import { antdIconList, parkIconList } from './icons.ts' import { antdIconList, parkIconList } from './icons.ts'
import { createContext, ProviderProps, useContext, useReducer, useMemo, useCallback } from 'react' import { createContext, ProviderProps, useContext, useReducer, useMemo, useCallback } from 'react'
export const ICON_RESET = Symbol.for('ICON_RESET')
export interface State { export interface State {
/** /**
* @title * @title
*/ */
icon?: IconUnit;
icon?: IconUnit | typeof ICON_RESET ;
/** /**
* @title * @title
*/ */
@ -80,11 +82,12 @@ type Actions = {
isEmptyIconParkList: boolean; isEmptyIconParkList: boolean;
} }
// 创建reducer函数 // 创建reducer函数
const reducer = (state: State, action: Action) => {
const reducer = (state: State, action: Action): State => {
switch (action.type) { switch (action.type) {
case 'resetIcon': case 'resetIcon':
return { ...state, icon: undefined }
return { ...state, icon: ICON_RESET }
case 'togglePanel': case 'togglePanel':
return { ...state, open: action.payload ?? !state.open } return { ...state, open: action.payload ?? !state.open }
case 'selectIcon': case 'selectIcon':
@ -100,6 +103,7 @@ const reducer = (state: State, action: Action) => {
} }
} }
export const PickerContextProvider = ({ value: propValue, children }: ProviderProps<ContextValue>) => { export const PickerContextProvider = ({ value: propValue, children }: ProviderProps<ContextValue>) => {
const [ state, dispatch ] = useReducer(reducer, { const [ state, dispatch ] = useReducer(reducer, {

24
src/components/icon/picker/index.tsx

@ -1,23 +1,27 @@
import { Popover, PopoverProps } from 'antd' import { Popover, PopoverProps } from 'antd'
import { FC, useEffect } from 'react'
import { FC, memo, useEffect } from 'react'
import Display from './Display.tsx' import Display from './Display.tsx'
import PickerPanel from './PickerPanel' import PickerPanel from './PickerPanel'
import { PickerContextProvider, usePickerContext } from './context.tsx'
import { ICON_RESET, PickerContextProvider, usePickerContext } from './context.tsx'
import { IconUnit } from '@/components/icon/types.ts'
interface PickerProps extends Partial<PopoverProps> { interface PickerProps extends Partial<PopoverProps> {
value?: string, value?: string,
onChange?: (value: string) => void, onChange?: (value: string) => void,
} }
const IconPicker: FC = (props: PickerProps) => {
const IconPicker: FC = memo((props: PickerProps) => {
const { state, actions: { selectIcon, togglePanel } } = usePickerContext() const { state, actions: { selectIcon, togglePanel } } = usePickerContext()
const { value, onChange } = props const { value, onChange } = props
useEffect(() => { useEffect(() => {
if (onChange) {
onChange(state.icon ? `${state.icon.type}:${state.icon.componentName}` : '')
if (onChange && state.icon) {
if (state.icon === ICON_RESET) {
return onChange('')
}
const icon = state.icon as IconUnit
onChange(state.icon ? `${icon.type}:${icon.componentName}` : '')
} }
}, [ state.icon ]) }, [ state.icon ])
@ -26,7 +30,7 @@ const IconPicker: FC = (props: PickerProps) => {
if (value) { if (value) {
const [ type, componentName ] = value.split(':') const [ type, componentName ] = value.split(':')
selectIcon({ type, componentName } as any) selectIcon({ type, componentName } as any)
}else{
} else {
selectIcon(null as any) selectIcon(null as any)
} }
}, [ value ]) }, [ value ])
@ -47,10 +51,10 @@ const IconPicker: FC = (props: PickerProps) => {
<Display/> <Display/>
</Popover> </Popover>
) )
}
})
export default (props: PickerProps) => {
export default memo((props: PickerProps) => {
return <PickerContextProvider value={{} as any}> return <PickerContextProvider value={{} as any}>
<IconPicker {...props as any}/> <IconPicker {...props as any}/>
</PickerContextProvider> </PickerContextProvider>
}
})

5
src/pages/system/menus/index.tsx

@ -151,7 +151,10 @@ const Menus = () => {
label={t('system.menus.form.name', '别名')} name={'name'}> label={t('system.menus.form.name', '别名')} name={'name'}>
<Input placeholder={t('system.menus.form.name', '别名')}/> <Input placeholder={t('system.menus.form.name', '别名')}/>
</Form.Item> </Form.Item>
<Form.Item label={t('system.menus.form.icon', '图标')} name={'icon'}>
<Form.Item label={t('system.menus.form.icon', '图标')} name={'icon'}
shouldUpdate={(prev: any, next: any) => {
return prev.icon !== next.icon
}}>
<IconPicker placement={'left'}/> <IconPicker placement={'left'}/>
</Form.Item> </Form.Item>
<Form.Item label={t('system.menus.form.sort', '排序')} name={'sort'}> <Form.Item label={t('system.menus.form.sort', '排序')} name={'sort'}>

Loading…
Cancel
Save