Jak poprawnie używać memo()?

0

Hej, mam komponent BoldButton i komponent MenuButton jak ponizej:

type Props = {
  editor: Editor;
};

export const BoldButton = memo(({ editor }: Props) => {
  return (
    <MenuButton
      icon={<BoldIcon />}
      command={() => editor.chain().focus().toggleBold().run()}
      disabled={!editor.can().toggleBold()}
      active={editor.isActive('bold')}
      tooltip={{
        content: (
          <TooltipContent title={_t('commands.bold')} shortcut='Mod-B' />
        ),
      }}
    />
  );
});

export interface ButtonProps extends React.HTMLAttributes<typeof Button> {
  icon?: JSX.Element | null;
  command?: () => boolean | void;
  disabled?: boolean;
  active?: boolean;
  tooltip?: {
    content: JSX.Element | null | string;
    placement?: 'top' | 'bottom' | 'left' | 'right';
  };
  text?: JSX.Element;
  dropdown?: {
    className?: string;
    isDropdownButton?: boolean;
    isDropdownItem?: boolean;
    dropdownContent?: JSX.Element;
    isOpen?: boolean;
    setIsOpen?: (isOpen: boolean) => void;
    dropdownIcon?: boolean;
    nested?: boolean;
    placement?: 'top' | 'bottom' | 'left' | 'right';
  };
  modal?:
    | {
        isModalButton?: boolean;
        modalContent?: JSX.Element;
        isOpen?: boolean;
        setIsOpen?: (isOpen: boolean) => void;
        onOpenChange?: Function;
      }
    | undefined;
}

export const MenuButton = memo(forwardRef<HTMLButtonElement, ButtonProps>(
  (
    {
      id,
      className,
      icon,
      command,
      disabled = false,
      active = false,
      tooltip,
      text,
      dropdown,
      modal,
    },
    ref
  ) => {
    const classNames = cn(
      'inline-flex items-center text-sm justify-center rounded-[4px] font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50',
      'text-base hover:bg-editor-btn-hover text-editor-btn-text hover:bg-[var(--editor-btn-hover)] active:bg-[var(--editor-btn-active)] [&_svg_*]:fill-foreground p-[2px]',
      className,
      active && !dropdown?.isDropdownButton
        ? 'bg-[var(--editor-btn-active)] hover:bg-[var(--editor-btn-active)]'
        : '',
      disabled
        ? 'opacity-50 cursor-not-allowed hover:bg-initial active:bg-initial'
        : '',
      dropdown?.isDropdownItem ? '' : '',
      '[&[aria-expanded=true]]:bg-[var(--editor-btn-active)]'
    );
...

Problem jest taki ze jak dodam memo do BoldButton to nigdy sie on nie rerenderuje (czyli ta defaultowa funkcja do porownywania propsow pewnie zwraca z jakiegos powodu zawsze to samo dla obiektu editor ktory jest dosc zlozony). Sprobowalem wiec opakowac MenuButton w memo ale tutaj z kolei komponent jest zawsze rerenderowany mimo ze propsy ktora pochodza z komponentu BoldButton sa takie same. Ktos moze wie o co moze chodzic? Jak to zrobic po bozemu zeby MenuButton sie nie rerenderowal za kazdym razem? Spowalnia to troche moja aplikacje bo mam duzo takich przyciskow w edytorze i sa one rerenderowane co klik klawitaury

1

React domyślnie porównuje jedynie referencje obiektów za pomocą Object.is(), więc póki nie zmieni się referencja to komponent się nie odświeży.

Możesz stworzyć własną funkcję, która porówna to w lepszy sposób

const MenuButton = memo(
  () => {
    // komponent ...
  },
  (oldProps, newProps) => {
    // funkcja musi zwrócić true lub false

    return oldProps.editor.xxx === newProps.editor.xxx;
  }
);

https://react.dev/reference/react/memo
https://react.dev/reference/react/useMemo
https://react.dev/reference/react/useCallback

0

Najlepiej w ogóle nie używać nemo(), chyba że masz jakiś bardzo konkretny powód ku temu.

1 użytkowników online, w tym zalogowanych: 0, gości: 1