Info

  • zustand ์‚ฌ์šฉ
    • ์‚ฌ์šฉ ์ด์œ  : ํƒ€ ์ƒํƒœ๊ด€๋ฆฌ๋ณด๋‹ค ๋Ÿฌ๋‹ ์ปค๋ธŒ๊ฐ€ ๋‚ฎ๊ณ  ๊ด€๋ฆฌ ํฌ์ธํŠธ๊ฐ€ ์ ์Œ.
  • store์˜ ๊ตฌ์กฐ๋Š” ๋‹จ์ˆœํ•˜๊ฒŒ ๋ฐ์ดํ„ฐ์˜ CRUD๋งŒ ๋‹ด๋‹น
    • ๋ณต์žกํ•œ ๋กœ์ง๋“ค์€ ๋ชจ๋‘ service layer์—์„œ ์ฒ˜๋ฆฌํ•จ.
    • ์—ญํ• ์ƒ์œผ๋กœ๋Š” ํ™”๋ฉด์—์„œ ๊ตฌ๋…์ค‘์ธ repository๋ผ๊ณ  ๋ณผ ์ˆ˜ ์žˆ์Œ.

Creation

  • ์ƒ๋‹จ์— interface ์ •์˜ ํ•„์š”.
  • use{name}Store.ts ๋„ค์ด๋ฐ ๊ทœ์น™ ์‚ฌ์šฉ.
  • ๋‚ด๋ถ€ fields ๋„ค์ด๋ฐ ๊ทœ์น™์€ ๋”ฐ๋กœ ์—†์ด ์ €์žฅํ•  ๊ฐ’์— ๋”ฐ๋ผ ๋„ค์ด๋ฐ ์ค‘โ€ฆ
  • ๊ตฌ์„ฑ
    • Object
      • ์ €์žฅํ•  ๊ฐ’ ์ž์ฒด (์ดˆ๊ธฐ ๊ฐ’ ์ง€์ • ํ•„์š”.)
    • Object state change functions
      • Update - ๋ณ€๊ฒฝํ•  ๊ฐ’ ์„ธํŒ…
      • Delete - ์ดˆ๊ธฐ ๊ฐ’์œผ๋กœ ๋‹ค์‹œ ์„ธํŒ…
      • Ect Functions - ์ถ”๊ฐ€์ ์ธ Functions

example

useShceduleStore.ts
import { Schedule } from '@typings/Schedule'  
import { create } from 'zustand/react'  
  
interface ScheduleStore {  
  schedules: Schedule[]  
  setSchedules: (schedules: Schedule[]) => void  
  addSchedules: (schedule: Schedule) => void  
  deleteSchedules: (id: number) => void  
  modifySchedules: (id: number, schedule: Schedule) => void  
}  
  
const useScheduleStore = create<ScheduleStore>(set => ({  
  schedules: [],  
  setSchedules: schedules => set({ schedules }),  
  addSchedules: schedule => set(state => ({ schedules: [...state.schedules, schedule] })),  
  deleteSchedules: id =>  
    set(state => ({ schedules: [...state.schedules.filter(schedule => schedule.id != id)] })),  
  modifySchedules: (id, schedule) => {  
    set(state => ({  
      schedules: state.schedules.map(stateSchedule =>  
        stateSchedule.id == id ? schedule : stateSchedule,  
      ),  
    }))  
  },  
}))  
  
export default useScheduleStore

Usage

  • ๊ด€๋ฆฌ ํฌ์ธํŠธ๋ฅผ ์„œ๋น„์Šค ๋กœ์ง์— ๊ฐ•์ œ์‹œํ‚ค๊ธฐ ์œ„ํ•ด์„œ modelView์—์„œ๋งŒ ์‚ฌ์šฉ ๊ฐ€๋Šฅ.
    • ์ด์™ธ์˜ ์‚ฌ์šฉ์ฒ˜์—์„œ๋Š” modelView์—์„œ ๋ฆฌํ„ด ์‹œ์ผœ์ค€ ๊ฐ’์„ ๊ฐ„์ ‘์ ์œผ๋กœ ์‚ฌ์šฉํ•ด์•ผํ•จ.
  • ์ดˆ๊ธฐ ๊ฐ’์€ ๋น„๋™๊ธฐ๊ฐ€ ํ•„์š”ํ•œ ๊ฒฝ์šฐ์—๋Š” null ๋˜๋Š” [](๋นˆ array)๋กœ ์ดˆ๊ธฐํ™”ํ•˜๊ณ  modelView์—์„œ init() function์„ ํ†ตํ•ด ๋‹ค์‹œ ํ• ๋‹น.
  • selector๋ฅผ ํ†ตํ•ด ๊ฐ’์„ ๋ฐ”์ธ๋”ฉ ํ•ด์•ผ ํ•จ.
    • selector๋กœ ํ™”๋ฉด์— ํ•„์š”ํ•œ state๋ฅผ ์ง€์ •ํ•จ์— ๋”ฐ๋ผ ํ•ด๋‹น state๊ฐ€ ๋ณ€ํ•˜๋Š” ์‹œ์ ์—๋งŒ ๋ฆฌ๋ Œ๋”๋ง ๊ฐ€๋Šฅ.
    • ๋งŽ์€ ๊ฐ’์„ selector๋ฅผ ํ†ตํ•ด ๊ฐ€์ ธ์™€ ๋ถ„ํ•ด ํ• ๋‹นํ•  ๊ฒฝ์šฐ, useShallow๋กœ ์–•์€ ๋น„๊ต๋ฅผ ํ•ด์•ผ ๋ถˆํ•„์š”ํ•œ loop๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์Œ.
  • store์˜ ๊ฐ’์€ BE์—์„œ ์ „๋‹ฌํ•ด์ค€ ๊ฐ’ ์ž์ฒด๋ฅผ ์ €์žฅํ•˜๊ฑฐ๋‚˜ FE์—์„œ ์‚ฌ์šฉํ•˜๊ธฐ ํŽธํ•œ ์œˆ์‹œ ๊ฐ’์œผ๋กœ ์ €์žฅํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํ™”๋ฉด์—์„œ ๋‹ค๋ฅธ format์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ, useMemo๋ฅผ ํ†ตํ•ด format์„ ๋ณ€๊ฒฝํ•˜์—ฌ ์‚ฌ์šฉํ•ด์•ผํ•จ.
    • ๊ผญ ํ•„์š”ํ•œ ๊ฒฝ์šฐ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด store์˜ ๊ฐ’์€ ๋˜๋„๋ก ๋ณ€๊ฒฝํ•˜๋ฉด ์•ˆ๋จ.

example

useMonthlyCalendarViewModel.ts
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