1
0
Fork 0
mirror of https://github.com/muerwre/vault-frontend.git synced 2025-04-25 04:46:40 +07:00

fixed sortables rerendering

This commit is contained in:
Fedor Katurov 2022-07-14 12:09:35 +07:00
parent f3fa88d72c
commit c58b4feb4a
5 changed files with 110 additions and 80 deletions

View file

@ -1,4 +1,4 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback, useMemo } from 'react';
import { AudioPlayer } from '~/components/media/AudioPlayer'; import { AudioPlayer } from '~/components/media/AudioPlayer';
import { AudioUpload } from '~/components/upload/AudioUpload'; import { AudioUpload } from '~/components/upload/AudioUpload';
@ -17,6 +17,29 @@ interface SortableAudioGridProps {
onDelete: (file_id: IFile['id']) => void; onDelete: (file_id: IFile['id']) => void;
onTitleChange: (file_id: IFile['id'], title: string) => void; onTitleChange: (file_id: IFile['id'], title: string) => void;
} }
const renderItem = ({
item,
key,
onDelete,
onTitleChange,
}: {
item: IFile;
key?: string | number;
onDelete?: (id: IFile['id']) => void;
onTitleChange?: (file_id: IFile['id'], title: string) => void;
}) => (
<AudioPlayer file={item} onDelete={onDelete} isEditing onTitleChange={onTitleChange} key={key} />
);
const renderLocked = ({ locked }: { locked: UploadStatus }) => (
<AudioUpload
id={locked.id}
is_uploading
title={locked.name}
progress={locked.progress}
key={locked.id}
/>
);
const SortableAudioGrid: FC<SortableAudioGridProps> = ({ const SortableAudioGrid: FC<SortableAudioGridProps> = ({
items, items,
@ -26,31 +49,8 @@ const SortableAudioGrid: FC<SortableAudioGridProps> = ({
onSortEnd, onSortEnd,
onTitleChange, onTitleChange,
}) => { }) => {
const renderItem = useCallback<FC<{ item: IFile; key?: string | number }>>( const renderItemProps = useMemo(() => ({ onDelete, onTitleChange }), [onDelete, onTitleChange]);
({ item, key }) => ( const renderLockedProps = useMemo(() => ({}), []);
<AudioPlayer
file={item}
onDelete={onDelete}
isEditing
onTitleChange={onTitleChange}
key={key}
/>
),
[onTitleChange, onDelete]
);
const renderLocked = useCallback<FC<{ locked: UploadStatus }>>(
({ locked }) => (
<AudioUpload
id={locked.id}
is_uploading
title={locked.name}
progress={locked.progress}
key={locked.id}
/>
),
[]
);
return ( return (
<SortableList <SortableList
@ -59,7 +59,9 @@ const SortableAudioGrid: FC<SortableAudioGridProps> = ({
getID={it => it.id} getID={it => it.id}
getLockedID={it => it.id} getLockedID={it => it.id}
renderItem={renderItem} renderItem={renderItem}
renderItemProps={renderItemProps}
renderLocked={renderLocked} renderLocked={renderLocked}
renderLockedProps={renderLockedProps}
onSortEnd={onSortEnd} onSortEnd={onSortEnd}
className={className} className={className}
/> />

View file

@ -12,29 +12,38 @@ import { SortableItem } from '../SortableItem';
import styles from './styles.module.scss'; import styles from './styles.module.scss';
interface SortableGridProps<T extends {}, R extends {}> { interface SortableGridProps<
items: T[]; ItemRendererProps extends {},
locked: R[]; LockedRendererProps extends {},
getID: (item: T) => number | string; Item extends {},
getLockedID: (locked: R) => number | string; Locked extends {}
renderItem: FC<{ item: T }>; > {
renderLocked: FC<{ locked: R }>; items: Item[];
onSortEnd: (newVal: T[]) => void; locked: Locked[];
getID: (item: Item) => number | string;
getLockedID: (locked: Locked) => number | string;
renderItem: FC<ItemRendererProps & { item: Item }>;
renderItemProps: ItemRendererProps;
renderLocked: FC<LockedRendererProps & { locked: Locked }>;
renderLockedProps: LockedRendererProps;
onSortEnd: (newVal: Item[]) => void;
className?: string; className?: string;
size?: number; size?: number;
} }
const SortableGrid = <T, R>({ const SortableGrid = <RIP, RLP, I, L>({
items, items,
locked, locked,
getID, getID,
getLockedID, getLockedID,
className, className,
renderItem, renderItem,
renderItemProps,
renderLocked, renderLocked,
renderLockedProps,
onSortEnd, onSortEnd,
size, size,
}: SortableGridProps<T, R>) => { }: SortableGridProps<RIP, RLP, I, L>) => {
const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions( const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions(
items, items,
getID, getID,
@ -66,17 +75,23 @@ const SortableGrid = <T, R>({
draggingItem && getID(item) === getID(draggingItem) ? styles.dragging : undefined draggingItem && getID(item) === getID(draggingItem) ? styles.dragging : undefined
} }
> >
{createElement(renderItem, { item })} {createElement(renderItem, { ...renderItemProps, item })}
</SortableItem> </SortableItem>
))} ))}
{locked.map(item => {locked.map(item =>
createElement(renderLocked, { locked: item, key: getLockedID(item) }) createElement(renderLocked, {
...renderLockedProps,
locked: item,
key: getLockedID(item),
})
)} )}
<DragOverlay> <DragOverlay>
{draggingItem ? ( {draggingItem ? (
<DragOverlayItem>{createElement(renderItem, { item: draggingItem })}</DragOverlayItem> <DragOverlayItem>
{createElement(renderItem, { ...renderItemProps, item: draggingItem })}
</DragOverlayItem>
) : null} ) : null}
</DragOverlay> </DragOverlay>
</div> </div>

View file

@ -1,4 +1,4 @@
import React, { FC, useCallback } from 'react'; import React, { FC, useCallback, useMemo } from 'react';
import { ImageUpload } from '~/components/upload/ImageUpload'; import { ImageUpload } from '~/components/upload/ImageUpload';
import { ImagePresets } from '~/constants/urls'; import { ImagePresets } from '~/constants/urls';
@ -18,6 +18,19 @@ interface SortableImageGridProps {
className?: string; className?: string;
size?: number; size?: number;
} }
const renderItem = ({ item, onDelete }: { item: IFile; onDelete: (fileId: number) => void }) => (
<ImageUpload id={item.id} thumb={getURL(item, ImagePresets.cover)} onDrop={onDelete} />
);
const renderLocked = ({
locked,
onDelete,
}: {
locked: UploadStatus;
onDelete: (fileId: number) => void;
}) => (
<ImageUpload thumb={locked.thumbnail} onDrop={onDelete} progress={locked.progress} is_uploading />
);
const SortableImageGrid: FC<SortableImageGridProps> = ({ const SortableImageGrid: FC<SortableImageGridProps> = ({
items, items,
@ -27,24 +40,7 @@ const SortableImageGrid: FC<SortableImageGridProps> = ({
onSortEnd, onSortEnd,
size, size,
}) => { }) => {
const renderItem = useCallback<FC<{ item: IFile }>>( const props = useMemo(() => ({ onDelete }), [onDelete]);
({ item }) => (
<ImageUpload id={item.id} thumb={getURL(item, ImagePresets.cover)} onDrop={onDelete} />
),
[]
);
const renderLocked = useCallback<FC<{ locked: UploadStatus }>>(
({ locked }) => (
<ImageUpload
thumb={locked.thumbnail}
onDrop={onDelete}
progress={locked.progress}
is_uploading
/>
),
[]
);
return ( return (
<SortableGrid <SortableGrid
@ -53,7 +49,9 @@ const SortableImageGrid: FC<SortableImageGridProps> = ({
getID={it => it.id} getID={it => it.id}
getLockedID={it => it.id} getLockedID={it => it.id}
renderItem={renderItem} renderItem={renderItem}
renderItemProps={props}
renderLocked={renderLocked} renderLocked={renderLocked}
renderLockedProps={props}
onSortEnd={onSortEnd} onSortEnd={onSortEnd}
className={className} className={className}
size={size} size={size}

View file

@ -1,36 +1,45 @@
import React, { createElement, FC } from "react"; import React, { createElement, FC } from 'react';
import { closestCenter, DndContext, DragOverlay } from "@dnd-kit/core"; import { closestCenter, DndContext, DragOverlay } from '@dnd-kit/core';
import { SortableContext, verticalListSortingStrategy } from "@dnd-kit/sortable"; import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable';
import classNames from "classnames"; import classNames from 'classnames';
import { DragOverlayItem } from "~/components/sortable/DragOverlayItem"; import { DragOverlayItem } from '~/components/sortable/DragOverlayItem';
import { SortableItem } from "~/components/sortable/SortableItem"; import { SortableItem } from '~/components/sortable/SortableItem';
import { useSortableActions } from "~/hooks/sortable"; import { useSortableActions } from '~/hooks/sortable';
import styles from "./styles.module.scss"; import styles from './styles.module.scss';
interface SortableListProps<T extends {}, R extends {}> { interface SortableListProps<
items: T[]; RenderItemProps extends {},
locked: R[]; RenderLockedProps extends {},
getID: (item: T) => number | string; Item extends {},
getLockedID: (locked: R) => number | string; Locked extends {}
renderItem: FC<{ item: T }>; > {
renderLocked: FC<{ locked: R }>; items: Item[];
onSortEnd: (newVal: T[]) => void; locked: Locked[];
getID: (item: Item) => number | string;
getLockedID: (locked: Locked) => number | string;
renderItem: FC<RenderItemProps & { item: Item }>;
renderItemProps: RenderItemProps;
renderLocked: FC<RenderLockedProps & { locked: Locked }>;
renderLockedProps: RenderLockedProps;
onSortEnd: (newVal: Item[]) => void;
className?: string; className?: string;
} }
const SortableList = <T, R>({ const SortableList = <RIP, RLP, I, L>({
items, items,
locked, locked,
getID, getID,
getLockedID, getLockedID,
className, className,
renderItem, renderItem,
renderItemProps,
renderLocked, renderLocked,
renderLockedProps,
onSortEnd, onSortEnd,
}: SortableListProps<T, R>) => { }: SortableListProps<RIP, RLP, I, L>) => {
const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions( const { sensors, onDragEnd, onDragStart, draggingItem, ids } = useSortableActions(
items, items,
getID, getID,
@ -54,17 +63,23 @@ const SortableList = <T, R>({
draggingItem && getID(item) === getID(draggingItem) ? styles.dragging : undefined draggingItem && getID(item) === getID(draggingItem) ? styles.dragging : undefined
} }
> >
{createElement(renderItem, { item, key: getID(item) })} {createElement(renderItem, { ...renderItemProps, item, key: getID(item) })}
</SortableItem> </SortableItem>
))} ))}
{locked.map(item => {locked.map(item =>
createElement(renderLocked, { locked: item, key: getLockedID(item) }) createElement(renderLocked, {
...renderLockedProps,
locked: item,
key: getLockedID(item),
})
)} )}
<DragOverlay> <DragOverlay>
{draggingItem ? ( {draggingItem ? (
<DragOverlayItem>{createElement(renderItem, { item: draggingItem })}</DragOverlayItem> <DragOverlayItem>
{createElement(renderItem, { ...renderItemProps, item: draggingItem })}
</DragOverlayItem>
) : null} ) : null}
</DragOverlay> </DragOverlay>
</div> </div>

File diff suppressed because one or more lines are too long