diff --git a/package.json b/package.json index 8cdf4c1..9b5805f 100644 --- a/package.json +++ b/package.json @@ -103,5 +103,8 @@ "component", "react" ], - "packageManager": "pnpm@9.12.0" + "packageManager": "pnpm@9.12.0", + "dependencies": { + "fast-deep-equal": "^3.1.3" + } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 606a20c..b02dd6f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@use-gesture/react': specifier: ^10.3.1 version: 10.3.1(react@18.3.1) + fast-deep-equal: + specifier: ^3.1.3 + version: 3.1.3 devDependencies: '@babel/core': specifier: ^7.25.7 diff --git a/src/SchedulerBody/NowMarker.tsx b/src/SchedulerBody/NowMarker.tsx index 79181a1..ab486d9 100644 --- a/src/SchedulerBody/NowMarker.tsx +++ b/src/SchedulerBody/NowMarker.tsx @@ -3,32 +3,37 @@ import dayjs, { Dayjs } from "dayjs"; import React, { useEffect, useMemo, useState } from "react"; import { UnknownSchedulerController } from "../controller/controller"; -export function NowMarkerController({ - markerComponent, - distanceCalculator, -}: { - markerComponent: React.FC; - distanceCalculator: UnknownSchedulerController["calculateDistancePercentage"]; -}) { - const Marker = markerComponent; - const [now, setNow] = useState(dayjs()); +export const NowMarkerController = React.memo( + ({ + markerComponent, + distanceCalculator, + }: { + markerComponent: React.FC; + distanceCalculator: UnknownSchedulerController["calculateDistancePercentage"]; + }) => { + const Marker = markerComponent; + const [now, setNow] = useState(dayjs()); - const nowLeft = useMemo(() => { - const distance = distanceCalculator(now, "left"); - if (!distance) return undefined; - return `${distance}%`; - }, [distanceCalculator, now]); + const nowLeft = useMemo(() => { + const distance = distanceCalculator(now, "left"); + if (!distance) return undefined; + return `${distance}%`; + }, [distanceCalculator, now]); - useEffect(() => { - const timeout = setTimeout(() => setNow(dayjs()), 1000); + useEffect(() => { + const timeout = setTimeout(() => setNow(dayjs()), 1000); - return () => { - clearTimeout(timeout); - }; - }); - if (!nowLeft) return null; - return ; -} + return () => { + clearTimeout(timeout); + }; + }); + if (!nowLeft) return null; + return ; + }, + (prev, next) => + prev.markerComponent == next.markerComponent && + prev.distanceCalculator == next.distanceCalculator, +); export interface NowMarkerProps { left: MantineStyleProps["left"]; diff --git a/src/SchedulerBody/SchedulerBody.tsx b/src/SchedulerBody/SchedulerBody.tsx index 8a3564c..ac30346 100644 --- a/src/SchedulerBody/SchedulerBody.tsx +++ b/src/SchedulerBody/SchedulerBody.tsx @@ -1,7 +1,7 @@ import { Box, Flex, MantineStyleProps, Paper } from "@mantine/core"; import { useWindowVirtualizer } from "@tanstack/react-virtual"; import { Dayjs } from "dayjs"; -import React, { useMemo, useRef } from "react"; +import React, { useContext, useMemo, useRef } from "react"; import { SchedulerController, SchedulerDisplayUnit, @@ -71,6 +71,7 @@ function SchedulerBodyRow({ momentStyle, subMomentCount, dataIdAccessor, + entryComponent, }: { data: TData[]; resourcesCount: number; @@ -95,7 +96,7 @@ function SchedulerBodyRow({ const rowRef = useRef(null); const controller = useControllerContext(); const getDataId = useStringAccessor(dataIdAccessor); - + const resource = useContext(resourceContext); const filteredData = useMemo( () => data.filter((item) => getDataResourceId(item).includes(resourceId)), [data, getDataResourceId, resourceId], @@ -128,6 +129,8 @@ function SchedulerBodyRow({ return ( ({ h="80%" right={`${endDistance}%`} display={display} + resource={resource} /> ); })} diff --git a/src/SchedulerBody/SchedulerEntry/SchedulerEntry.tsx b/src/SchedulerBody/SchedulerEntry/SchedulerEntry.tsx index 5d4e9d4..6118c7b 100644 --- a/src/SchedulerBody/SchedulerEntry/SchedulerEntry.tsx +++ b/src/SchedulerBody/SchedulerEntry/SchedulerEntry.tsx @@ -1,8 +1,6 @@ import { MantineStyleProps, Paper, useMantineTheme } from "@mantine/core"; -import { useContext } from "react"; -import { resourceContext } from "../contexts"; -import { schedulerEntryContext } from "./context"; - +import deepEqual from "fast-deep-equal"; +import React from "react"; export interface SchedulerEntryProps { top: NonNullable; left: NonNullable; @@ -35,11 +33,30 @@ export const DefaultSchedulerEntry: SchedulerEntryComponent = ({ ); }; -export function SchedulerEntryRenderer( - props: Omit, "resource">, -) { - const CustomSchedulerEntry: SchedulerEntryComponent = - useContext(schedulerEntryContext); - const resource = useContext(resourceContext); - return ; +interface SchedulerEntryRendererProps + extends SchedulerEntryProps { + CustomSchedulerEntry: SchedulerEntryComponent; } + +function SchedulerEntryRenderer_({ + CustomSchedulerEntry, + ...props +}: SchedulerEntryRendererProps) { + return ; +} + +export const SchedulerEntryRenderer = React.memo( + (props: SchedulerEntryRendererProps) => ( + + ), + (prev, next) => { + return ( + prev.display == next.display && + prev.left === next.left && + prev.right === next.right && + prev.CustomSchedulerEntry == next.CustomSchedulerEntry && + deepEqual(prev.resource, next.resource) && + deepEqual(prev.data, next.data) + ); + }, +);