mirror of
https://github.com/webadderallorg/Recordly.git
synced 2026-09-25 07:16:02 +00:00
useMemo instead of expensive filter operations done everytime
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { useTimelineContext } from "dnd-timeline";
|
||||
import { useCallback, useEffect, useRef, useState } from "react";
|
||||
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
||||
import type { AudioPeaksData } from "./useAudioPeaks";
|
||||
|
||||
interface AudioWaveformProps {
|
||||
@@ -11,7 +11,7 @@ interface AudioWaveformProps {
|
||||
* Automatically syncs with the timeline's visible range so the waveform
|
||||
* scrolls and zooms together with the clip items above it.
|
||||
*/
|
||||
export default function AudioWaveform({ peaks }: AudioWaveformProps) {
|
||||
function AudioWaveformComponent({ peaks }: AudioWaveformProps) {
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const { range } = useTimelineContext();
|
||||
const [resizeKey, setResizeKey] = useState(0);
|
||||
@@ -87,3 +87,5 @@ export default function AudioWaveform({ peaks }: AudioWaveformProps) {
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(AudioWaveformComponent);
|
||||
|
||||
@@ -293,6 +293,12 @@ const TimelineEditor = forwardRef<TimelineEditorHandle, TimelineEditorProps>(
|
||||
keyShortcuts,
|
||||
isTimelineFocusedRef,
|
||||
});
|
||||
const handleToolbarAddAnnotation = useCallback(() => {
|
||||
handleAddAnnotation();
|
||||
}, [handleAddAnnotation]);
|
||||
const handleToolbarAddAudio = useCallback(() => {
|
||||
void handleAddAudio();
|
||||
}, [handleAddAudio]);
|
||||
|
||||
return (
|
||||
<TimelineEditorShell
|
||||
@@ -313,10 +319,8 @@ const TimelineEditor = forwardRef<TimelineEditorHandle, TimelineEditorProps>(
|
||||
onOpenCropEditor={onOpenCropEditor}
|
||||
onAddZoom={handleAddZoom}
|
||||
onSuggestZooms={handleSuggestZooms}
|
||||
onAddAnnotation={() => handleAddAnnotation()}
|
||||
onAddAudio={() => {
|
||||
void handleAddAudio();
|
||||
}}
|
||||
onAddAnnotation={handleToolbarAddAnnotation}
|
||||
onAddAudio={handleToolbarAddAudio}
|
||||
onSplitClip={handleSplitClip}
|
||||
cropLabel={t("sections.crop", "Crop")}
|
||||
/>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { useTimelineContext } from "dnd-timeline";
|
||||
import { useMemo } from "react";
|
||||
import { memo, useMemo } from "react";
|
||||
import { calculateAxisScale } from "../../core/time";
|
||||
|
||||
interface ClipMarkerOverlayProps {
|
||||
videoDurationMs: number;
|
||||
}
|
||||
|
||||
export default function ClipMarkerOverlay({ videoDurationMs }: ClipMarkerOverlayProps) {
|
||||
function ClipMarkerOverlayComponent({ videoDurationMs }: ClipMarkerOverlayProps) {
|
||||
const { direction, range, valueToPixels } = useTimelineContext();
|
||||
const sideProperty = direction === "rtl" ? "right" : "left";
|
||||
|
||||
@@ -51,3 +51,5 @@ export default function ClipMarkerOverlay({ videoDurationMs }: ClipMarkerOverlay
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default memo(ClipMarkerOverlayComponent);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Plus } from "@phosphor-icons/react";
|
||||
import { useMemo, type MouseEventHandler } from "react";
|
||||
import { memo, useMemo, type MouseEventHandler } from "react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import AudioWaveform from "../../AudioWaveform";
|
||||
import glassStyles from "../../ItemGlass.module.css";
|
||||
@@ -46,7 +46,7 @@ interface TimelineCanvasRowsProps {
|
||||
onZoomRowClick: MouseEventHandler<HTMLDivElement>;
|
||||
}
|
||||
|
||||
export function TimelineCanvasRows({
|
||||
function TimelineCanvasRowsComponent({
|
||||
items,
|
||||
videoDurationMs,
|
||||
selectAllBlocksActive,
|
||||
@@ -69,32 +69,56 @@ export function TimelineCanvasRows({
|
||||
onZoomRowMouseLeave,
|
||||
onZoomRowClick,
|
||||
}: TimelineCanvasRowsProps) {
|
||||
const zoomItems = useMemo(() => items.filter((item) => item.rowId === ZOOM_ROW_ID), [items]);
|
||||
const clipItems = useMemo(() => items.filter((item) => item.rowId === CLIP_ROW_ID), [items]);
|
||||
const annotationItems = useMemo(
|
||||
() => items.filter((item) => isAnnotationTrackRowId(item.rowId)),
|
||||
[items],
|
||||
);
|
||||
const audioItems = useMemo(() => items.filter((item) => isAudioTrackRowId(item.rowId)), [items]);
|
||||
const { clipItems, zoomItems, annotationRows, audioRows } = useMemo(() => {
|
||||
const nextClipItems: TimelineRenderItem[] = [];
|
||||
const nextZoomItems: TimelineRenderItem[] = [];
|
||||
const annotationBuckets = new Map<number, TimelineRenderItem[]>();
|
||||
const audioBuckets = new Map<number, TimelineRenderItem[]>();
|
||||
|
||||
const audioRowIds = useMemo(
|
||||
() =>
|
||||
Array.from(
|
||||
new Set(audioItems.map((item) => getAudioTrackRowId(getAudioTrackIndex(item.rowId)))),
|
||||
).sort((left, right) => getAudioTrackIndex(left) - getAudioTrackIndex(right)),
|
||||
[audioItems],
|
||||
);
|
||||
const annotationRowIds = useMemo(
|
||||
() =>
|
||||
Array.from(
|
||||
new Set(
|
||||
annotationItems.map((item) =>
|
||||
getAnnotationTrackRowId(getAnnotationTrackIndex(item.rowId)),
|
||||
),
|
||||
),
|
||||
).sort((left, right) => getAnnotationTrackIndex(left) - getAnnotationTrackIndex(right)),
|
||||
[annotationItems],
|
||||
);
|
||||
for (const item of items) {
|
||||
if (item.rowId === CLIP_ROW_ID) {
|
||||
nextClipItems.push(item);
|
||||
continue;
|
||||
}
|
||||
if (item.rowId === ZOOM_ROW_ID) {
|
||||
nextZoomItems.push(item);
|
||||
continue;
|
||||
}
|
||||
if (isAnnotationTrackRowId(item.rowId)) {
|
||||
const trackIndex = getAnnotationTrackIndex(item.rowId);
|
||||
const bucket = annotationBuckets.get(trackIndex);
|
||||
if (bucket) bucket.push(item);
|
||||
else annotationBuckets.set(trackIndex, [item]);
|
||||
continue;
|
||||
}
|
||||
if (isAudioTrackRowId(item.rowId)) {
|
||||
const trackIndex = getAudioTrackIndex(item.rowId);
|
||||
const bucket = audioBuckets.get(trackIndex);
|
||||
if (bucket) bucket.push(item);
|
||||
else audioBuckets.set(trackIndex, [item]);
|
||||
}
|
||||
}
|
||||
|
||||
const annotationRowsSorted = Array.from(annotationBuckets.entries())
|
||||
.sort(([left], [right]) => left - right)
|
||||
.map(([trackIndex, rowItems]) => ({
|
||||
rowId: getAnnotationTrackRowId(trackIndex),
|
||||
items: rowItems,
|
||||
}));
|
||||
const audioRowsSorted = Array.from(audioBuckets.entries())
|
||||
.sort(([left], [right]) => left - right)
|
||||
.map(([trackIndex, rowItems]) => ({
|
||||
rowId: getAudioTrackRowId(trackIndex),
|
||||
items: rowItems,
|
||||
}));
|
||||
|
||||
return {
|
||||
clipItems: nextClipItems,
|
||||
zoomItems: nextZoomItems,
|
||||
annotationRows: annotationRowsSorted,
|
||||
audioRows: audioRowsSorted,
|
||||
};
|
||||
}, [items]);
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -166,10 +190,7 @@ export function TimelineCanvasRows({
|
||||
))}
|
||||
</Row>
|
||||
|
||||
{annotationRowIds.map((rowId, index) => {
|
||||
const rowItems = annotationItems.filter(
|
||||
(item) => getAnnotationTrackRowId(getAnnotationTrackIndex(item.rowId)) === rowId,
|
||||
);
|
||||
{annotationRows.map(({ rowId, items: rowItems }, index) => {
|
||||
return (
|
||||
<Row
|
||||
key={rowId}
|
||||
@@ -194,10 +215,7 @@ export function TimelineCanvasRows({
|
||||
);
|
||||
})}
|
||||
|
||||
{audioRowIds.map((rowId, index) => {
|
||||
const rowItems = audioItems.filter(
|
||||
(item) => getAudioTrackRowId(getAudioTrackIndex(item.rowId)) === rowId,
|
||||
);
|
||||
{audioRows.map(({ rowId, items: rowItems }, index) => {
|
||||
return (
|
||||
<Row
|
||||
key={rowId}
|
||||
@@ -224,3 +242,5 @@ export function TimelineCanvasRows({
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
export const TimelineCanvasRows = memo(TimelineCanvasRowsComponent);
|
||||
|
||||
Reference in New Issue
Block a user