简体   繁体   English

React 功能组件与内部无状态类

[英]React Functional component with stateless class inside

I would like to ask or gather some important suggestions for this situation.对于这种情况,我想询问或收集一些重要的建议。

I wan't to create my own Datetimepicker react component.我不想创建自己的 Datetimepicker 反应组件。 I was searching some codes for easily constructing a calendar.我正在搜索一些代码以轻松构建日历。 Now I found some Regular Class which makes the calendar and I want to re-use it for creating my Datetimepicker component.现在我找到了一些制作日历的常规类,我想重新使用它来创建我的 Datetimepicker 组件。

Now I would like to ask/open for suggestion for better or good practice that would be logical for my component.现在我想就我的组件合乎逻辑的更好或良好实践征求/开放建议。

In the code below, I have a functional component with a stateless class Day inside of it and I tried to instantiate it for future use.在下面的代码中,我有一个功能组件,其中包含一个无状态类Day ,我尝试实例化它以备将来使用。 For me it works fine.对我来说,它工作正常。 Since I don't want to look my code very messy or make it fewer lines, Is there anyway to separate this Day stateless class to import it in my Functional component?由于我不想让我的代码看起来很凌乱或减少行数,所以无论如何要分离这个Day无状态类以将它导入到我的功能组件中? or any suggestions for this?.或对此有何建议? Or Can anyone explain to me if what am I doing is logically wrong or not, since I was using a Functional based component and putting a class inside of it.或者任何人都可以向我解释我所做的是否在逻辑上是错误的,因为我使用的是基于功能的组件并在其中放置了一个类。 I would like to hear some good advice for this to implement in much better way.我想听听一些好的建议,以便以更好的方式实施。

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 should not be dynamically created when possible.如果可能,不应动态创建类。 You'll get lots of individual instances tied to their own classes which are actually different despite having the same name.您将获得许多与它们自己的类相关联的实例,尽管它们具有相同的名称,但它们实际上是不同的。

Here, the only identifier Day uses from the outer scope of the functional component is the getWeekNumber , which is called in the constructor.在这里,Day 在功能组件的外部范围中使用的唯一标识符是getWeekNumber ,它在构造函数中被调用。 But getWeekNumber doesn't reference anything particular to a particular render either, so it can be moved out too - either to its own standalone function, or to the inside of Day.但是getWeekNumber也没有引用任何特定于特定渲染的东西,因此它也可以被移出 - 要么移到它自己的独立函数中,要么移到 Day 的内部。 You can do你可以做

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

and then remove Day and getWeekNumber from the functional component.然后从功能组件中删除 Day 和getWeekNumber

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM