ํฐ์คํ ๋ฆฌ ๋ทฐ
์์ ์์ผ, ์๊ฐ๋ง ๋ณด์ฌ์ฃผ๊ธฐ
์์์ผ๋ถํฐ ์์

const localizer = dateFnsLocalizer({
format,
parse,
startOfWeek: () => startOfWeek(new Date(), { weekStartsOn: 1 }), // ์์์ผ ์์
getDay,
locales,
});
์๊ฐ๋ง ๋ณด์ฌ์ฃผ๊ธฐ
<Calendar
localizer={localizer}
events={events} // ์ฌ๊ธฐ์ ์ด๋ฒคํธ ์ถ๊ฐ ๊ฐ๋ฅ
startAccessor='start'
endAccessor='end'
defaultView='month' // ๊ธฐ๋ณธ ๋ณด์ฌ์ฃผ๊ธฐ : ์๋ณ
views={['month']} // ์๊ฐ ๋ฌ๋ ฅ๋ง ๋ณด์ฌ์ฃผ๊ธฐ
style={{ height: 500 }}
/>

RBC ์ฃผ์ ์ปดํฌ๋ํธ
์ข์ธก ์๋จ์ ๋ ์ง ๋๊ธฐ๊ธฐ / ์ค๋ ๋ ์ง ๋ฒํผ์ ๋์ด ๋ฌ๋ ฅ์ ์ด๋์ ๊ตฌํํ๊ณ ์ถ์๋ค.
์ฌ๋ก๋ฅผ ์ฐพ๋ค๋ณด๋ RBC์ ์์๋ค์ ์ฌ๋ฌ ์ปดํฌ๋ํธ๋ก ์ชผ๊ฐ์ ์ฌ์ฉํ ์ ์๋ค๋ ๊ฒ์ ์๊ฒ๋์๋ค.
์ชผ๊ฐค ์ ์๋ ์ฃผ์ ์ปดํฌ๋ํธ๋ ๋ค์๊ณผ ๊ฐ๋ค.
components={{
toolbar, // ์๋จ ํด๋ฐ
event, // ์ด๋ฒคํธ ์
agenda: {
event, // agenda view์ ์ด๋ฒคํธ
},
timeSlotWrapper, // ์๊ฐ ์ฌ๋กฏ (์๊ฐ ์นธ)
dateCellWrapper, // ๋ ์ง ์
(์๊ฐ ๋ทฐ ์
)
day, // ์ผ๊ฐ ๋ทฐ
week, // ์ฃผ๊ฐ ๋ทฐ
month, // ์๊ฐ ๋ทฐ
}}
Toolbar์ props
๊ทธ ์ค ํด๋ฐ์ ํด๋นํ๋ ์์๋ฅผ ์์ธํ ์ดํด๋ณด๊ฒ ๋ค.
label, onNavigate, localizer, onView, date, view, views
label
- ํด๋ฐ ์ค์์ ๋ณดํต ๋ณด์ด๋ ํ์ฌ ๋ ์ง ๋ฒ์์ ํ ์คํธ (์: "April 2025")
- RBC ๋ด๋ถ์์ ์๋์ผ๋ก ๋ง๋ค์ด์ค
<span>{label}</span> // "April 2025"
onNavigate(action)
- ์ด์ /๋ค์/์ค๋ ๋ฒํผ ํด๋ฆญ ์ ์ฌ์ฉํ๋ ํจ์
- action ๊ฐ์ ๋ค์ ์ค ํ๋: 'PREV', 'NEXT', 'TODAY', 'DATE'
<button onClick={() => onNavigate('TODAY')}>Today</button>
<button onClick={() => onNavigate('PREV')}>{'<'}</button>
<button onClick={() => onNavigate('NEXT')}>{'>'}</button>
localizer
- ๋ฌ๋ ฅ์์ ์ฌ์ฉํ๋ ๋ ์ง/์๊ฐ ๊ด๋ จ ๊ธฐ๋ฅ๋ค์ ์ง์ญ(locale)์ ๋ง๊ฒ ์ฒ๋ฆฌ
- ๋ ์ง๋ฅผ "2025๋ 4์ 7์ผ"์ฒ๋ผ ํฌ๋งท
- ์์ผ์ "Mon", "Tue"๊ฐ ์๋๋ผ "์", "ํ"์ฒ๋ผ ๋ณ๊ฒฝ
- ์ฃผ์ ์์ ์์ผ์ ์์์ผ๋ก ์ค์
onView(viewName)
- ๋ทฐ(์: month, week, day, agenda)๋ฅผ ์ ํํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ ํจ์
- views props์ ํด๋น ๋ทฐ๊ฐ ๋ฑ๋ก๋์ด์์ด์ผ ์๋ํ๋ค.
<button onClick={() => onView('month')}>Month</button>
<button onClick={() => onView('week')}>Week</button>
date
- ํ์ฌ ๋ณด์ฌ์ง๊ณ ์๋ ์บ๋ฆฐ๋ ๋ ์ง ๊ธฐ์ค์ Date ๊ฐ์ฒด (์: 2025-04-01)
- ์ง์ ๋ ์ง ์กฐ์ํ๊ณ ์ถ์ ๋ ์ ์ฉ
view
- ํ์ฌ ๋ณด๊ณ ์๋ ๋ทฐ์ ์ด๋ฆ ('month', 'week', 'day', 'agenda')
if (view === 'month') {
// ์๊ฐ ๋ทฐ ์ ์ฉ UI ๋ณด์ฌ์ฃผ๊ธฐ
}
views
- ์ฌ์ฉ ๊ฐ๋ฅํ ๋ทฐ๋ค์ ๋ฐฐ์ด (์: ['month', 'week', 'day'])
- ์ด๊ฑธ๋ก view ์ ํ ๋ฒํผ์ ๋์ ์ผ๋ก ์์ฑํ ์ ์๋ค.
์ด์ , ๋ค์ ๋ฌ ๋๊ธฐ๊ธฐ
onNavigate()์ date๋ฅผ ์ฌ์ฉํ๋ค.
๊ณต์ ๋ฌธ์์์๋ onNavigate์ date๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ์ค๋ช ํ๊ณ ์๋ค.


๋์ ํจ๊ป ์ฌ์ฉ๋๋ฉฐ onNavigate ํจ์๋ฅผ ํตํด date๋ฅผ ์ ์ดํ๋ ๊ฒ์ด๋ค.
๋์ ์ผ๋ก ๋ณํ๋ ๋ ์ง๋ฅผ state๋ก ๋๊ณ onNavigate ํจ์๋ก ์ด๋ฅผ ์ ์ดํ๋ค.
// MainCalendar.tsx
const MainCalendar = () => {
const [month, setMonth] = useState(new Date());
return (
<div>
<Calendar
localizer={localizer}
events={events}
date={month} // ํ์ฌ ๋ ์ง(๋ฌ)
onNavigate={(newDate) => {
setMonth(newDate); // ๋ ์ง(๋ฌ) ๋ณ๋
}}
startAccessor='start'
endAccessor='end'
defaultView='month'
views={['month']}
components={{
toolbar: CustomToolbar, // ์๋จ ํด๋ฐ ๋ถ๋ฆฌ
}}
style={{ height: 500 }}
/>
</div>
);
};
// CustomToolbar.tsx
import React from 'react';
import { NavigateAction } from 'react-big-calendar';
interface Props {
label: string;
onNavigate: (action: NavigateAction) => void;
}
const CustomToolbar = ({ label, onNavigate }: Props) => {
return (
<div>
<button onClick={() => onNavigate('PREV')}>โฌ
๏ธ</button>
<span>{label}</span>
<button onClick={() => onNavigate('NEXT')}>โก๏ธ</button>
<button onClick={() => onNavigate('TODAY')}>Today</button>
</div>
);
};
export default CustomToolbar;
๐ค ๋ฒํผ์ CustomToolbar ์์ ์๋๋ฐ ์ธ๋ถ์ date๋ onNavigate๋ฅผ ๋์ด๋ ์๋๋๋ ์ด์ ๊ฐ ๋ญ๊น?
์บ๋ฆฐ๋ ์ปดํฌ๋ํธ๊ฐ ํด๋ฐ์๊ฒ props๋ฅผ ๋๊ฒจ์ฃผ๊ธฐ ๋๋ฌธ์ ๋์ด ์ฐ๊ฒฐ๋ ์ ์๋ ๊ฒ์ด๋ค.
์ข ๋ ์์ธํ ์ดํด๋ณด์๋ฉด,
<Calendar
date={month} // ๐๐ป ํ์ฌ ๋ ์ง state
onNavigate={(newDate) => setMonth(newDate)} // ๐๐ป ๋ ์ง ๋ณ๊ฒฝ ํจ์
components={{ toolbar: CustomToolbar }} // ๐๐ป ์ปค์คํ
ํด๋ฐ ์ ์ฉ
/>
- ์ฌ์ฉ์๊ฐ ๋ฒํผ์ ํด๋ฆญํ๋ค.
- CustomToolbar์์ onNavigate('PREV')
- RBC ์์ฒด์ ์ผ๋ก PREV์ ๋ง๋ newDate ๊ณ์ฐ
- Calendar์ onNavigate(newDate) ํธ์ถ
- Calendar์ setMonth(newDate) → state ์ ๋ฐ์ดํธ
- Calendar ๋ค์ ๋ ๋๋ง + CustomToolbar๋ ๋ฆฌ๋ ๋๋ง
localizer ์ค์ : 2025 4์
์ฌ์ค ์ต์๋จ์ ์ ๋ฆฌํ ๊ฒ์ฒ๋ผ ํด๋ฐ๊ฐ ์๋ ์บ๋ฆฐ๋์์ ์์์ผ ์์์ ๊ตฌํํ๋ค.
๋ฐ๋ผ์ ์บ๋ฆฐ๋์์์ ํด๋ฐ์์์ localizer ์ญํ ์ฐจ์ด๋ ๊ถ๊ธํ๋ค.
๐์บ๋ฆฐ๋์์์ localizer
์ ์ฒด ์บ๋ฆฐ๋์ ๋ ์ง ์ฒ๋ฆฌ ๊ธฐ์ค์ ์ ํ๋ค.
<Calendar localizer={localizer} ... />
- ๊ธฐ๋ณธ ๋ ์ง ํฌ๋งทํ , ์์ ์์ผ, ์ธ์ด/๋ก์ผ์ผ, ๋ ์ง ๊ณ์ฐ ๋ก์ง ๋ฑ์ Calendar์ ์ ๋ฌ
- ๋ด๋ถ์ ์ผ๋ก localizer.format(...), localizer.startOfWeek(...) ๋ฑ์ ์ฌ์ฉํด์ ๋ ์ง ์ฒ๋ฆฌ
- ์์ ์์ผ์ ์์์ผ: startOfWeek: () => startOfWeek(new Date(), { weekStartsOn: 1 })
๐ํด๋ฐ์์์ localizer
ํด๋ฐ์ ํ์๋๋ ๋ ์ง ํ ์คํธ ํฌ๋งทํ๋ค.
const CustomToolbar = ({ localizer }: ToolbarProps<Event>) => {
const label = localizer.format(date, 'yyyy MMMM', 'ko-KR');
};
- Calendar์์ ๋๊ฒจ์ค localizer ๊ฐ์ฒด๊ฐ ํด๋ฐ์๋ ์ ๋ฌ
- ํด๋ฐ๋ ๋ณดํต ํ์ฌ ๋ ์ง์ ๋ง๋ ๋ฌธ์์ด(label) ์ ํ์ํ๊ธฐ ๋๋ฌธ์,
localizer.format(...) ์ ์ง์ ํธ์ถํด์ ์ฌ์ฉ์๊ฐ ๋ณด๊ธฐ ์ฌ์ด ํ ์คํธ๋ฅผ ๋ง๋ ๋ค. - "2025๋ 4์" ํ๊ธ๋ก ํ์ํ๊ณ ์ถ์ ๋ : ์ง์ format์ ํธ์ถํด์ ์ฒ๋ฆฌ
์ง๊ธ ํ์ํ ๊ฑด ๋ ์ง๋ฅผ "2025๋ 4์"์ฒ๋ผ ํฌ๋งท ํ๋ ๊ธฐ๋ฅ์ด๋ค.
- localizer.format(date, formatString, culture)์ ์ฌ์ฉํ์ฌ ์ํ๋ ํํ๋ก ๋ ์ง ์ถ๋ ฅ ๊ฐ๋ฅํ๋ค.

ํ์ง๋ง,
์บ๋ฆฐ๋์ const localizer = dateFnsLocalizer() ๋ช ์๋ ํ๊ณ , ํด๋ฐ์๋ ๋ง๊ฒ ์ ์ฉํ์ง๋ง ๊ณ์ํด์ 'message' ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค.
์์ธ์ dateFnsLocalizer()๋ก ์์ฑํ localizer์ Calendar์ generic ํ์ ์ด ์๋ก ์ ๋ง์์ ์๊ธฐ๋ ๋ฌธ์ ์ด๋ค.
์ฌ์ค ๊ทธ ๋ด์ฉ์ ์์ฃผ ์์ธํ ํ์ ํ์ง ๋ชปํ์ง๋ง ๋๋ต ๋ค์๊ณผ ๊ฐ์ด ์ดํดํ๋ค.
์บ๋ฆฐ๋์์๋ id๊ฐ ํฌํจ๋ supabase ๋ฐ์ดํฐ๋ฅผ ์ฌ์ฉํ๊ธฐ ๋๋ฌธ์ CalendarEventType(id ํฌํจ) ํ์ ์ ์ฌ์ฉํ์ง๋ง,
ํด๋ฐ์๋ id๋ฅผ ์ฌ์ฉํ์ง ์๋๋ค. ๋ฐ๋ผ์ ๋์ ํ์ ์ด ๋ง์ง ์์์ ์๊ธฐ๋ ๋ฌธ์

๋ฐ๋ผ์ ๋ฌธ์ ๋ฅผ ๋ค์๊ณผ ๊ฐ์ด ํด๊ฒฐํ์๋ค.
- ํด๋ฐ์ ํ์ ์ ์บ๋ฆฐ๋์ ๊ฐ๊ฒ ๋ช ์ํด์ฃผ๊ธฐ => ์บ๋ฆฐ๋์ components > toolbar ์์ ํ์ ์ค๋ฅ ์ฌ๋ผ์ง
- date-fns์์ ํ๊ธ ๋ ์ง๊ฐ ๊ฐ์ ธ์ค๊ธฐ
import { CalendarEventType } from '@/types/plans';
import { format } from 'date-fns';
import { ko } from 'date-fns/locale';
import { ToolbarProps } from 'react-big-calendar';
//โญ๏ธ์บ๋ฆฐ๋์ ํ์
๋ง์ถค(id ์ ์ค๋ก ์ธํ ์ค๋ฅ)โญ๏ธ
const CustomToolbar = ({ date, onNavigate }: ToolbarProps<CalendarEventType>) => {
const customLabel = format(date, 'yyyy MMMM', { locale: ko });
return (
<div>
<button onClick={() => onNavigate('PREV')}>โฌ
๏ธ</button>
<span>{customLabel}</span>
<button onClick={() => onNavigate('NEXT')}>โก๏ธ</button>
<button onClick={() => onNavigate('TODAY')}>Today</button>
</div>
);
};
export default CustomToolbar;
์ด์ฐจํผ ์ปค์คํฐ๋ง์ด์ง ํ๋ ๊ฒ์ด๊ธฐ ๋๋ฌธ์ ๊ผญ localizer์ ์ฝ๋ฉ์ด์ง ์๊ณ date-fns์์ ํ๊ธ๋ก ๋ง๊ฒ ๋ฒ์ญํ๋ ๋ฐฉ๋ฒ์ ํํ๋ค.
'Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
| [์ฌ๋๋ณ_Day10] ์๋ณ๋ก ๋ฐ์ดํฐ ์บ์ฑํ๊ธฐ (0) | 2025.04.09 |
|---|---|
| [์ฌ๋๋ณ_Day9] ๊ณตํด์ผ ๋ฌ๋ ฅ์ ์ ์ฉํ๊ธฐ (feat.๊ณต๊ณต๋ฐ์ดํฐ) (1) | 2025.04.09 |
| [์ฌ๋๋ณ_Day6] ์บ๋ฆฐ๋์ ์ผ์ ๋ํ๋ด๊ธฐ - UTC (0) | 2025.04.04 |
| [์ฌ๋๋ณ_Day5] RBC ํํค์น๊ธฐ 4 - ๊ธฐ์กด ์คํ์ผ๊ณผ ์ปค์คํฐ๋ง์ด์ง (0) | 2025.04.03 |
| [์ฌ๋๋ณ_Day4] RBC ํํค์น๊ธฐ 3 - ์บ๋ฆฐ๋๋ ์ CSR? (0) | 2025.04.02 |