Info
- MVVM ํจํด ์ฌ์ฉ
- Model
- View
- ViewModel
Structure
Model
class
- ์ฃผ๋ก constructor ๊ฐ ํ์ํ ๊ฒฝ์ฐ์ ์ฌ์ฉ๋จ.
- get ๊ณผ ๊ฐ์ด custom function์ด ํ์ํ ๊ฒฝ์ฐ์๋ ์ฌ์ฉ๋จ.
- ์์ ์ธ DateOfCalendar.ts ์์๋ ์์ฑ ๊ณผ์ ์์ object to class ํํ ๊ตฌ์กฐ๋ฅผ class๋ฅผ ํตํด ์ ์ํ๊ณ ๊ฐ์ ํ๊ธฐ ์ํด์ ์ฌ์ฉ.
- ์ ์ฐํ ์์ฑ์ด ํ์ ์์ด ์ ํด์ง ํจํด์ผ๋ก ์์ฑํด์ผํ๋ model์์ ์ฌ์ฉ
example
import { getWeekdayByCode, weekday, Weekday } from '@typings/constants/Weekday'
import dayjs from 'dayjs'
import { ScheduleOfDate } from '@typings/ScheduleOfDate'
import dateFormatUtil from '@utils/date/dateFormatUtil'
export class DateOfCalendar {
year: number
month: number
day: number
weekday: Weekday
schedules: Array<ScheduleOfDate | null>
holiday: null | string = null
constructor(
date: {
year?: number
month?: number
day?: number
schedules?: Array<ScheduleOfDate | null>
holiday?: null | string
} = {},
) {
const now = dateFormatUtil.getDate()
const {
year = now.year(),
month = now.month() + 1,
day = now.date(),
schedules = [],
holiday = null,
} = date
const targetDate = date ? dayjs(`${year}-${month}-${day}`) : now
this.year = targetDate.year()
this.month = targetDate.month() + 1
this.day = targetDate.date()
this.weekday = getWeekdayByCode(targetDate.day())
this.schedules = schedules
this.holiday = holiday
}
get isSaturday() {
return this.weekday.code == weekday.SATURDAY.code
}
get isSunday() {
return this.weekday.code == weekday.SUNDAY.code || this.holiday
}
isSameWeekday = (weekday: Weekday) => this.weekday.code == weekday.code
isToday = (now: dayjs.Dayjs) =>
now.year() == this.year && now.month() + 1 == this.month && now.date() == this.day
}type
- ์ฃผ๋ก ํํ๋ง ํ์ํ ๊ฒฝ์ฐ ์ฌ์ฉ.
- ์ถ๊ฐ์ ์ธ ๋ก์ง ์ ์ ์๋ ์์ํ field์ ์งํฉ.
example
export type Token = {
accessToken: string | null
refreshToken: string | null
}View
- ์ค์ ํ์ด์ง ๊ตฌํ๋ถ
- ์๋น์ค ๋ก์ง์ ์ต์ํํ๊ณ ํ๋ฉด์ ๊ทธ๋ฆฌ๊ธฐ ์ํ Element ๊ตฌ์ฑ ์์๋ง ์ฌ์ฉํ ์ ์๋๋ก ๊ตฌ์ฑ.
- utils์ ์ ์๋ ๊ณตํต util function๋ค์ ํธ์ถ ๊ฐ๋ฅ
- ํ์์ ๋ฐ๋ผ component๋ก ๋ถ๋ฆฌ.
- ์ฌ์ฉ์ ๋ฐ๋ผ name ๋ถ๋ฅ
- page์ธ ๊ฒฝ์ฐ, {name}Page.tsx
- component์ธ ๊ฒฝ์ฐ, {name}.tsx
example
import React, { useEffect } from 'react'
import useMonthlyCalendarViewModel from '@views/calendar/monthlyCalendar/useMonthlyCalendarViewModel'
import './monthlyCalendarPage.scss'
import MonthlyCalendarHeader from '@views/calendar/monthlyCalendar/components/monthlyCalendarHeader/MonthlyCalendarHeader'
import MonthlyCalendarBody from '@views/calendar/monthlyCalendar/components/monthlyCalendarBody/MonthlyCalendarBody'
import SchedulePopups from '@views/calendar/popup/SchedulePopups'
const MonthlyCalendarPage: React.FC = () => {
const { calculatedMonthlyCalendar: calendar, currentDate, init } = useMonthlyCalendarViewModel()
useEffect(() => {
if (
calendar == null ||
calendar.type != 'MONTHLY' ||
!(currentDate.year == calendar.year && currentDate.month == calendar.month)
)
init()
}, [currentDate])
if (!calendar) return null
return (
<>
<div className="monthly-calendar">
<MonthlyCalendarHeader />
<MonthlyCalendarBody calendar={calendar} />
<SchedulePopups /> </div>
</>
)
}
export default MonthlyCalendarPageViewModel
- page ๋๋ component์์ ํ์ํ service ๋ก์ง ๋๋ ์ํ ๊ด๋ฆฌ ์ ๋ณด(store์์ ์ํธ์์ฉ)๋ฅผ ๊ด๋ฆฌํ๋ ๋ถ๋ถ
- use{name}ViewModel.ts ๋ก ์ ์
- ํ๋ฉด์์ ํ์ํ store ์ ๋ณด๋ฅผ ์ ๋ฌํด์ฃผ๊ฑฐ๋ ์์ ํ๋ ์์ ๋ viewModel์์๋ง ๊ฐ๋ฅ
example
import calendarRepository from '@repositories/CalendarRepository'
import { useMemo } from 'react'
import { Calendar } from '@typings/Calendar'
import dateFormatUtil from '@utils/date/dateFormatUtil'
import { ScheduleOfDate } from '@typings/ScheduleOfDate'
import scheduleRepository from '@repositories/ScheduleRepository'
import useCalendarStore from '@stores/useCalendarStore'
import useScheduleStore from '@stores/useScheduleStore'
import { useShallow } from 'zustand/react/shallow'
import useCalendarSelectStore from '@stores/useCalendarSelectStore'
import { scheduleType } from '@typings/constants/ScheduleType'
const useMonthlyCalendarViewModel = () => {
const currentDate = useCalendarSelectStore(useShallow(state => state.currentDate))
const { calendar, setCalendar } = useCalendarStore(
useShallow(state => ({
calendar: state.calendar,
setCalendar: state.setCalendar,
})),
)
const { schedules, setSchedules } = useScheduleStore(
useShallow(state => ({
schedules: state.schedules,
setSchedules: state.setSchedules,
})),
)
const { stringToDate } = dateFormatUtil
const calculatedMonthlyCalendar: null | Calendar = useMemo(() => {
if (!calendar) return null
const copyCalendar: Calendar = Object.assign(calendar)
const schedulesOfDate = schedules
.sort(a => (a.type == scheduleType.TASK ? 1 : -1))
.sort((a, b) => (stringToDate(a.startedAt).isAfter(stringToDate(b.startedAt)) ? 1 : -1))
.map((schedule, index) => schedule.getScheduleOfDateList(index + 1))
.flatMap(schedules => schedules)
let prevSchedules: ScheduleOfDate[] = []
copyCalendar.dates.forEach(date => {
const resultSchedules: ScheduleOfDate[] = []
const targetSchedules: ScheduleOfDate[] = schedulesOfDate.filter(
schedule =>
schedule.year == date.year && schedule.month == date.month && schedule.day == date.day,
)
let prevIndex = 0
// ๋น ์์ null ์ธํ
=> ํ๋ฉด์์ ์ฌ์ฉ ํ ๊ฒฝ์ฐ, null ๊ฐ์ ๋ํ ๋์ ํ์.
targetSchedules.forEach(schedule => {
const prevScheduleIndex = prevSchedules.findIndex(
targetSchedule => targetSchedule != null && targetSchedule.id == schedule.id,
)
for (let i = prevIndex; i < prevScheduleIndex; i++) resultSchedules.push(null)
prevIndex = prevScheduleIndex + 1
})
// ์ผ์ ์ธํ
targetSchedules.forEach(schedule => {
const prevScheduleIndex = prevSchedules.findIndex(
targetSchedule => targetSchedule != null && targetSchedule.id == schedule.id,
)
if (prevScheduleIndex != -1) {
resultSchedules[prevScheduleIndex] = schedule
} else {
const nullIndex = resultSchedules.findIndex(targetSchedule => targetSchedule == null)
if (nullIndex != -1) {
resultSchedules[nullIndex] = schedule
} else {
resultSchedules.push(schedule)
} }
})
prevSchedules = resultSchedules
date.schedules = resultSchedules
})
return copyCalendar
}, [calendar, schedules])
const setMonthlyCalendar = async () => {
setCalendar(null)
setSchedules([])
const monthlyCalendar = await calendarRepository.getMonthlyCalendar({
year: currentDate.year,
month: currentDate.month,
})
const scheduleList = await scheduleRepository.findByDate({
year: currentDate.year,
month: currentDate.month,
})
setCalendar(monthlyCalendar)
setSchedules(scheduleList)
}
const init = async () => {
console.log('init!!')
await setMonthlyCalendar()
}
return {
calculatedMonthlyCalendar,
currentDate,
init,
}
}
export default useMonthlyCalendarViewModel