如何阻止我的组件在开发中被制作两次

How to stop my component from being made twice in development

我正在关注这个 tutorial 以在 React

中制作一个 javascript 日历

我有一个工作日历UI,代码如下

// https://medium.com/@nitinpatel_20236/challenge-of-building-a-calendar-with-pure-javascript-a86f1303267d
import { useState, useEffect, useRef, useMemo } from 'react'
import type { NextPage } from 'next'
import Head from 'next/head'
import styles from '../styles/Home.module.scss'

const months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
// console.log('render')

const Home: NextPage = () => {
  const today = useMemo(() => new Date(), []);
  const [currentMonth, setCurrentMonth] = useState(today.getMonth())
  const [currentYear, setCurrentYear] = useState(today.getFullYear())
  const calendarBodyRef = useRef<HTMLDivElement>(null)

  // check how many days in a month code from https://dzone.com/articles/determining-number-days-month
  const daysInMonth = (iMonth: number, iYear: number) => {
    return 32 - new Date(iYear, iMonth, 32).getDate()
  }

  useEffect(() => {
    const showCalendar = (month: number, year: number) => {
      const firstDay = (new Date(year, month)).getDay()
      const calendarBody = calendarBodyRef.current

      // creating all cells
      let date = 1;
      for (let i = 0; i < 6; i++) {
        // creates a table row
        const row = document.createElement("div")
        row.classList.add(styles.row)
        //creating individual cells, filing them up with data.
        for (let j = 0; j < 7; j++) {
          if (i === 0 && j < firstDay) {
            const cell = document.createElement("div")
            cell.classList.add(styles.cell)
            const cellText = document.createTextNode("")
            cell.appendChild(cellText)
            row.appendChild(cell)
          } else if (date > daysInMonth(month, year)) {
            break
          } else {
            const cell = document.createElement("div")
            cell.classList.add(styles.cell)
            const cellText = document.createTextNode(String(date))
            if (date === today.getDate() && year === today.getFullYear() && month === today.getMonth()) {
              cell.classList.add(styles.currentDay)
            } // color today's date
            cell.appendChild(cellText)
            row.appendChild(cell)
            date++
          }
        }
        if (calendarBody) {
          calendarBody.appendChild(row) // appending each row into calendar body.
        }
      }
    }
    showCalendar(currentMonth, currentYear)
  }, [currentMonth, currentYear, today])

  return (
    <>
      <Head>
        <title>Calendar Budget App</title>
        <meta name="description" content="Generated by create next app" />
        <link rel="icon" href="/favicon.ico" />
      </Head>
      <div className={styles.calendarWrap}>
        <h2 className={styles.monthTitle}>{months[currentMonth]} {currentYear}</h2>
        <div className={styles.daysWrap}>
          <span>Sun</span>
          <span>Mon</span>
          <span>Tue</span>
          <span>Wed</span>
          <span>Thu</span>
          <span>Fri</span>
          <span>Sat</span>
        </div>
        <div ref={calendarBodyRef} className={styles.calendarBody}>
        </div>
      </div>
    </>
  )
}

export default Home

但是在开发中,我的日历制作了两次

我认为这是因为 React.StrictMode 在开发中,因为 useEffect 似乎是 运行ning 两次。如果我运行npm run buildnpm start模仿制作,我只看到一个日历

我的日历在开发中还有办法显示一次吗?

您遇到的问题是 useEffect 中的依赖项在新的渲染周期中发生变化,因此多次触发 showCalendar。

要保留您的代码并且仅 运行 它一次,您应该能够定义变量:

const today = ...
const currentMonth = ...
const currentYear = ...

并从 useEffect 中删除依赖项,因为它们不会更改:

showCalendar(currentMonth, currentYear)
  }, [])

但是useEffect完全没有必要,而且你的做法很奇怪。

就这样:

<div ref={calendarBodyRef} className={styles.calendarBody}>
                {months.map(month => {
                    return <div>[...your logic here]<div>
                })}
    </div>

或:

    const getMonthElement = (month) => {
          return <div>[your month logic]<div>
    }

...

    return(
        <div ref={calendarBodyRef} className={styles.calendarBody}>
            {months.map(month => {
                return <div>[...your logic here]<div>
            })}
        </div>
    )

希望对您有所帮助。