前端野人

我是Louis,自詡為野生的前端工程師,在網路中求生存

Make a Calendar React hook

發布於

使用 date-fns 開發 calendar hook

Moment vs date-fns

一般來說,只要有關時間的 lib 我們都會想到 moment,我一開始也是使用moment,但發現 moment 不太適合用在 react hook 上,主要原因是在於,moment mutable,假設把moment放到 useState 管理會發現,hook 不會刷新,但是 moment 的狀態會更新。

而我實際操作後,也參考了 moment vs date-fns 該文作者歸納出兩個 date-fns moment 好的優點:

1. immutable

2. size more smaller

所以我選擇用 date-fns 來設計。

Moment Demo

從這邊可以發現,當直接操作 moment,不用 setState 就可以更新 moment

demo

如果想了解更好的設計方法可參考:

demo

useCalendar

我原先有使用原生的 new Date 設計日曆,可參考這篇 MensWalk - Pure React Calendar

但是如果仔細看會發現,不夠乾淨,太過混雜,於是我重新改寫一遍。

切換月份

使用 date-fns 後切換月份就變得更加精簡及嚴謹,而且 pure 寫法因為是直接做數字加減所以還會有浮點數的問題。

pure

const [today, setToday] = useState(new Date());

const [currentMonth, setCurrentMonth] = useState(today.getMonth());
const [currentYear, setCurrentYear] = useState(today.getFullYear());

const setNextMonth = () => {
  if (currentMonth === 11) {
    setCurrentMonth(0);
    setCurrentYear(currentYear + 1);
  } else {
    setCurrentMonth(currentMonth + 1);
  }
};
const setPreMonth = () => {
  if (currentMonth === 0) {
    setCurrentYear(currentYear - 1);
    setCurrentMonth(11);
  } else {
    setCurrentMonth(currentMonth - 1);
  }
};


date-fns

const [today, setToday] = useState(new Date());

const setNextMonth = () => {
  setToday(addMonths(today, 1))
}

const setPreMonth = () => {
  setToday(subMonths(today, 1))
}

顯示當月日期

日期回傳 二維陣列,使用 date-fns 處理上更加好懂,我這邊還增加了 上個月 下個月的日期也一起放進來,這樣日期顯示上更加完整。

code

選擇日期

我預設日曆的資料格式為下,往後如果需要新增日期的操作可以更加彈性的新增。

let dateInfo = {                    
    otherMonth: false,                    
    date: null,                
}

測試

測試比較特別的點是在於,怎麼精準的測出當月的日曆,這邊我們只要抓,當天的星期及週數,帶入到 hooks days 中比對是否為同一天即可,這樣我們就不用測是不是整個陣列格式都一樣了。

code

Conclusion

改寫後的 useCalendar 更加完整,程式邏輯更加清楚,往後想要做進一步修正更加容易,如果想再 React 操作 時間相關的應用,date-fns 會是更好的選擇。

Demo

https://wildfrontend.github.io/useCalendar/?path=/story/calendar-test--demo

Source

https://github.com/wildfrontend/useCalendar

看不過癮?

一鍵登入,即可加入全球最優質中文創作社區