React Functional component with stateless class 内部

React Functional component with stateless class inside

我想针对这种情况询问或收集一些重要的建议。

我不想创建自己的 Datetimepicker React 组件。我正在搜索一些代码来轻松构建日历。现在我找到了一些制作日历的常规 Class,我想重新使用它来创建我的 Datetimepicker 组件。

现在我想 ask/open 征求对我的组件来说合乎逻辑的更好或良好做法的建议。

在下面的代码中,我有一个功能组件,里面有一个无状态 class Day,我试图实例化它以备将来使用。对我来说效果很好。因为我不想让我的代码看起来很乱或者减少行数,所以有没有办法把这个 Day stateless class 分开来导入我的 Functional 组件?或者对此有什么建议吗?或者任何人都可以向我解释我在做什么在逻辑上是否错误,因为我使用的是基于功能的组件并在其中放置了 class 。我想听听一些好的建议,以便以更好的方式实施。

import React, {useState} from "react";
import styles from "./Datetimepicker.module.scss";
import classNames from "classnames";
import CalendarSVG from "../../../styles/icons/Calendar/Calendar"

const Datetimepicker = (props) => {
  const {
    style,
    name,    
    color,
    size,    
    inputRef,
    errorMsg,
    helperMsg,
    placeholder,
    disabled,
    ...others
  } = props;

  
  const [addVisibility, setAddVisibility] = useState(false);

  const showCalendar = () => {
    setAddVisibility((prevState) => (!prevState));
  }

  const getWeekNumber = (date) => {
    const firstDayOfTheYear = new Date(date.getFullYear(), 0, 1);
    const pastDaysOfYear = (date - firstDayOfTheYear) / 86400000;
    
    return Math.ceil((pastDaysOfYear + firstDayOfTheYear.getDay() + 1) / 7)
  }

  class Day {
    constructor(date = null, lang = 'default') {
      date = date ?? new Date();    
      this.Date = date;
      this.date = date.getDate();
      this.day = date.toLocaleString(lang, { weekday: 'long'});
      this.dayNumber = date.getDay() + 1;
      this.dayShort = date.toLocaleString(lang, { weekday: 'short'});
      this.year = date.getFullYear();
      this.yearShort = date.toLocaleString(lang, { year: '2-digit'});
      this.month = date.toLocaleString(lang, { month: 'long'});
      this.monthShort = date.toLocaleString(lang, { month: 'short'});
      this.monthNumber = date.getMonth() + 1;
      this.timestamp = date.getTime();
      this.week = getWeekNumber(date);
    }
    
    get isToday() {
      return this.isEqualTo(new Date());
    }
    
    isEqualTo(date) {
      date = date instanceof Day ? date.Date : date;
      
      return date.getDate() === this.date &&
        date.getMonth() === this.monthNumber - 1 &&
        date.getFullYear() === this.year;
    }
    
    format(formatStr) {
      return formatStr
        .replace(/\bYYYY\b/, this.year)
        .replace(/\bYYY\b/, this.yearShort)
        .replace(/\bWW\b/, this.week.toString().padStart(2, '0'))
        .replace(/\bW\b/, this.week)
        .replace(/\bDDDD\b/, this.day)
        .replace(/\bDDD\b/, this.dayShort)
        .replace(/\bDD\b/, this.date.toString().padStart(2, '0'))
        .replace(/\bD\b/, this.date)
        .replace(/\bMMMM\b/, this.month)
        .replace(/\bMMM\b/, this.monthShort)
        .replace(/\bMM\b/, this.monthNumber.toString().padStart(2, '0'))
        .replace(/\bM\b/, this.monthNumber)
    }
  }

  const day = new Day();

  console.log('--day', day);

  return (
    <div className={styles.DatetimepickerWrapper}>
      <input
        className={classNames(
          styles.InputText,                
          errorMsg && styles.InputError,
          style ?? ""
        )}
        type="text"
        name={name}        
        placeholder={placeholder ?? "mm/dd/yyyy"}
        {...inputRef}
        {...others}
        disabled={disabled}        
      />
      <div className={addVisibility ? `${styles.CalendarVisible} ${styles.CalendarDropDown}` : `${styles.CalendarHidden}`}>
        <div className={styles.CalendarContainer}>
          <div className={styles.CalendarHeaderYear}>            
              <p>2022</p>            
          </div>
          <div className={styles.CalendarHeaderMonth}>
          <button type="button" className="prev-month" aria-label="previous month"></button>
            <h4 tabIndex="0" aria-label="current month">
              January
            </h4>
            <button type="button" className="prev-month" aria-label="next month"></button>
          </div>
          <div className={styles.CalendarDaysContainer}>
            <p>Test</p>
            <p>Test</p>
            <p>Test</p>
            <p>Test</p>
          </div>          
        </div>        
      </div>
      <CalendarSVG width={23} fill="#294197" className={styles.CalendarDateTimePickerIcon} onClick={() => showCalendar()}/>  
      {errorMsg && <span className={styles.ErrorMessage}>{errorMsg}</span>}
      {!errorMsg && helperMsg && (
        <span className={styles.HelperMessage}>{helperMsg}</span>
      )}
    </div>
  );
};

export default Datetimepicker;

A class 不应尽可能动态创建。你会得到许多与它们自己的 classes 相关联的单独实例,尽管它们具有相同的名称,但它们实际上是不同的。

在这里,Day 在功能组件的外部范围内使用的唯一标识符是 getWeekNumber,它在构造函数中调用。但是 getWeekNumber 也没有引用特定渲染的任何特定内容,因此它也可以移出 - 可以移到它自己的独立函数中,也可以移到 Day 的内部。你可以做到

class Day {
    constructor(date = null, lang = 'default') {
        date = date ?? new Date();
        this.Date = date;
        this.date = date.getDate();
        this.day = date.toLocaleString(lang, { weekday: 'long' });
        this.dayNumber = date.getDay() + 1;
        this.dayShort = date.toLocaleString(lang, { weekday: 'short' });
        this.year = date.getFullYear();
        this.yearShort = date.toLocaleString(lang, { year: '2-digit' });
        this.month = date.toLocaleString(lang, { month: 'long' });
        this.monthShort = date.toLocaleString(lang, { month: 'short' });
        this.monthNumber = date.getMonth() + 1;
        this.timestamp = date.getTime();
        this.week = this.getWeekNumber(date); // change this line
    }
    getWeekNumber(date) { // add this method
        const firstDayOfTheYear = new Date(date.getFullYear(), 0, 1);
        const pastDaysOfYear = (date - firstDayOfTheYear) / 86400000;
        return Math.ceil((pastDaysOfYear + firstDayOfTheYear.getDay() + 1) / 7)
    }
    // all the other code in Day is the same

然后从功能组件中删除 Day 和 getWeekNumber