Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/ScheduleContext.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { createContext, PropsWithChildren, useContext, useState } from "react";
import React, { createContext, PropsWithChildren, useContext, useMemo, useState } from "react";
import { Schedule } from "./types.ts";
import dummyScheduleMap from "./dummyScheduleMap.ts";

Expand All @@ -20,8 +20,11 @@ export const useScheduleContext = () => {
export const ScheduleProvider = ({ children }: PropsWithChildren) => {
const [schedulesMap, setSchedulesMap] = useState<Record<string, Schedule[]>>(dummyScheduleMap);

// Context 값을 메모이제이션하여 불필요한 리렌더링 방지
const value = useMemo(() => ({ schedulesMap, setSchedulesMap }), [schedulesMap]);

return (
<ScheduleContext.Provider value={{ schedulesMap, setSchedulesMap }}>
<ScheduleContext.Provider value={value}>
{children}
</ScheduleContext.Provider>
);
Expand Down
28 changes: 17 additions & 11 deletions src/ScheduleTable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import { Schedule } from "./types.ts";
import { fill2, parseHnM } from "./utils.ts";
import { useDndContext, useDraggable } from "@dnd-kit/core";
import { CSS } from "@dnd-kit/utilities";
import { ComponentProps, Fragment } from "react";
import { ComponentProps, Fragment, memo, useMemo } from "react";

interface Props {
tableId: string;
Expand All @@ -39,24 +39,30 @@ const TIMES = [
] as const;

const ScheduleTable = ({ tableId, schedules, onScheduleTimeClick, onDeleteButtonClick }: Props) => {
const dndContext = useDndContext();

const getColor = (lectureId: string): string => {
// 강의 ID에 따른 색상 매핑을 메모이제이션
const colorMap = useMemo(() => {
const lectures = [...new Set(schedules.map(({ lecture }) => lecture.id))];
const colors = ["#fdd", "#ffd", "#dff", "#ddf", "#fdf", "#dfd"];
return colors[lectures.indexOf(lectureId) % colors.length];
};
const map: Record<string, string> = {};
lectures.forEach((lectureId, index) => {
map[lectureId] = colors[index % colors.length];
});
return map;
}, [schedules]);

const dndContext = useDndContext();
const getColor = (lectureId: string): string => {
return colorMap[lectureId];
};

const getActiveTableId = () => {
const activeTableId = useMemo(() => {
const activeId = dndContext.active?.id;
if (activeId) {
return String(activeId).split(":")[0];
}
return null;
}

const activeTableId = getActiveTableId();
}, [dndContext.active?.id]);

return (
<Box
Expand Down Expand Up @@ -127,7 +133,7 @@ const ScheduleTable = ({ tableId, schedules, onScheduleTimeClick, onDeleteButton
);
};

const DraggableSchedule = ({
const DraggableSchedule = memo(({
id,
data,
bg,
Expand Down Expand Up @@ -175,6 +181,6 @@ const DraggableSchedule = ({
</PopoverContent>
</Popover>
);
}
});

export default ScheduleTable;
34 changes: 23 additions & 11 deletions src/ScheduleTables.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Button, ButtonGroup, Flex, Heading, Stack } from "@chakra-ui/react";
import ScheduleTable from "./ScheduleTable.tsx";
import { useScheduleContext } from "./ScheduleContext.tsx";
import SearchDialog from "./SearchDialog.tsx";
import { useState } from "react";
import { useCallback, useMemo, useState } from "react";

export const ScheduleTables = () => {
const { schedulesMap, setSchedulesMap } = useScheduleContext();
Expand All @@ -14,19 +14,34 @@ export const ScheduleTables = () => {

const disabledRemoveButton = Object.keys(schedulesMap).length === 1;

const duplicate = (targetId: string) => {
const duplicate = useCallback((targetId: string) => {
setSchedulesMap(prev => ({
...prev,
[`schedule-${Date.now()}`]: [...prev[targetId]]
}))
};
}, [setSchedulesMap]);

const remove = (targetId: string) => {
const remove = useCallback((targetId: string) => {
setSchedulesMap(prev => {
delete prev[targetId];
return { ...prev };
})
};
}, [setSchedulesMap]);

const handleScheduleTimeClick = useCallback((tableId: string, timeInfo: { day: string; time: number }) => {
setSearchInfo({ tableId, ...timeInfo });
}, []);

const handleDeleteButtonClick = useCallback((tableId: string, { day, time }: { day: string; time: number }) => {
setSchedulesMap((prev) => ({
...prev,
[tableId]: prev[tableId].filter(schedule => schedule.day !== day || !schedule.range.includes(time))
}));
}, [setSchedulesMap]);

const handleCloseSearch = useCallback(() => {
setSearchInfo(null);
}, []);

return (
<>
Expand All @@ -46,16 +61,13 @@ export const ScheduleTables = () => {
key={`schedule-table-${index}`}
schedules={schedules}
tableId={tableId}
onScheduleTimeClick={(timeInfo) => setSearchInfo({ tableId, ...timeInfo })}
onDeleteButtonClick={({ day, time }) => setSchedulesMap((prev) => ({
...prev,
[tableId]: prev[tableId].filter(schedule => schedule.day !== day || !schedule.range.includes(time))
}))}
onScheduleTimeClick={(timeInfo) => handleScheduleTimeClick(tableId, timeInfo)}
onDeleteButtonClick={(timeInfo) => handleDeleteButtonClick(tableId, timeInfo)}
/>
</Stack>
))}
</Flex>
<SearchDialog searchInfo={searchInfo} onClose={() => setSearchInfo(null)}/>
<SearchDialog searchInfo={searchInfo} onClose={handleCloseSearch}/>
</>
);
}
Loading