typescript 在开发实用程序类时,我是否应该提供不可变的API,以便与React之类的框架一起使用?

iklwldmw  于 2022-12-14  发布在  TypeScript
关注(0)|答案(1)|浏览(127)

目前,我正在开发DateWithoutTime类。对于这个问题,重要的是这个类具有由公共方法变异的私有字段。

this.state.dateWithoutTimeInstance.shiftBySpecificDaysCount({
  daysCount: 5,
  toFuture: true
});

虽然我已经省略了原始类的某些部分,但代码清单仍然太长,所以我将把它附加到问题的末尾。
在像React这样的框架中,我们不能改变对象。因此,我假设,在React中,需要根据旧变量创建新变量,而不是上面的代码,如:

let updatedDateWithoutTimeInstance: DateWithoutTime = new DateWithoutTime({
  year: this.state.dateWithoutTimeInstance.year,
  monthNumber__numerationFrom1: this.state.dateWithoutTimeInstance.monthNumber__numerationFrom1,
  dayOfMonth: this.state.dateWithoutTimeInstance.dayOfMonth
});

updatedDateWithoutTimeInstance.shiftBySpecificDaysCount({
  daysCount: 5,
  toFuture: true
});

this.setState((state) => {
  return { dateWithoutTimeInstance: updatedDateWithoutTimeInstance };
});

我们能不能写

this.state.dateWithoutTimeInstance.shiftBySpecificDaysCount({
  daysCount: 5,
  toFuture: true
});

React中?如果否,则需要提供不可变更新的方法,如:

this.setState((state) => {
  return { 
  // returns new instance
dateWithoutTimeInstance: 
this.state.dateWithoutTimeInstance.shiftBySpecificDaysCountImmutably({
  daysCount: 5,
  toFuture: true
});};
});

附录:“DateWithoutTime”类的部分列表

import type {
  MonthsNames
} from `@yamato-daiwa/ex-extensions`

import {
    DaysOfWeek,
    Logger,
    InvalidParameterValueError,
    getISO8601StringWithoutTimePart,
    getMonthNameByNumber,
    shiftDateBySpecificDaysCount,
    isNumber,
    isString,
    getMonthNumberByName
} from `@yamato-daiwa/ex-extensions`

class DateWithoutTime {

  protected _nativeDateObject!: Date;

  protected _year!: number;

  protected _monthName!: MonthsNames;
  protected _monthNumber__numerationFrom0!: number;
  protected _monthNumber__numerationFrom1!: number;
  protected _monthNumber__numerationFrom1__2Digits!: string;

  protected _dayOfMonth!: number;
  protected _dayOfMonth__2Digits!: string;

  protected _dayOfWeek!: DaysOfWeek;
  protected _dayOfWeekNumber__numerationFrom0AsSunday!: number;
  protected _dayOfWeekNumber__numerationFrom1AsSunday!: number;
  protected _dayOfWeekNumber__numerationFrom1AsSunday__2Digits!: string;

  public constructor(rawDateTime: number | string | Date | DateWithoutTime.DateDefinition) {

    try {

      if (isNumber(rawDateTime) || isString(rawDateTime) || rawDateTime instanceof Date) {
        this.nativeDateObject = new Date(rawDateTime);
      } else {
        this.nativeDateObject = DateWithoutTime.dateDefinitionToNativeDateObject(rawDateTime);
      }

    } catch (error: unknown) {

      Logger.throwErrorAndLog({
        errorInstance: new InvalidParameterValueError({
          parameterName: "rawDateTime",
          parameterNumber: 1
        }),
        title: InvalidParameterValueError.localization.defaultTitle,
        occurrenceLocation: "DateWithoutTime.constructor(rawDateTime)",
        wrappableError: error
      });

    }

  }

  public shiftBySpecificDaysCount(
    namedParameters: Readonly<
      { daysCount: number; } &
      (
        {
          toFuture: true;
          toPast?: undefined;
        } |
        {
          toPast: true;
          toFuture?: undefined;
        }
      )
    >
  ): this {

    this.nativeDateObject = shiftDateBySpecificDaysCount({
      initialDate: this._nativeDateObject,
      dayCount: namedParameters.daysCount,
      ...namedParameters.toFuture === true ? { toFuture: true } : { toPast: true }
    });

    return this;

  }

  public get year(): number { return this._year; }
  public get monthName(): MonthsNames { return this._monthName; }
  
  // Other getters...

  public get nativeDateObject(): Date { return this._nativeDateObject; }
  protected set nativeDateObject(value: Date) {

    this._nativeDateObject = value;

    this._year = this._nativeDateObject.getFullYear();

    this._monthNumber__numerationFrom0 = this._nativeDateObject.getMonth();
    this._monthNumber__numerationFrom1 = this._monthNumber__numerationFrom0 + 1;
    this._monthNumber__numerationFrom1__2Digits = this._monthNumber__numerationFrom1.toString().padStart(2, "0");

    this._monthName = getMonthNameByNumber({ targetMonthNumber: this._monthNumber__numerationFrom1, numerationFrom: 1 });

    this._dayOfMonth = this._nativeDateObject.getDate();
    this._dayOfMonth__2Digits = this._dayOfMonth.toString().padStart(2, "0");

    this._dayOfWeekNumber__numerationFrom0AsSunday = this._nativeDateObject.getDay();
    this._dayOfWeekNumber__numerationFrom1AsSunday = this._dayOfWeekNumber__numerationFrom0AsSunday + 1;
    this._dayOfWeekNumber__numerationFrom1AsSunday__2Digits =
        this._dayOfWeekNumber__numerationFrom1AsSunday.toString().padStart(2, "0");

    switch (this._dayOfWeekNumber__numerationFrom1AsSunday) {
      case 1: { this._dayOfWeek = DaysOfWeek.sunday; break; }
      case 2: { this._dayOfWeek = DaysOfWeek.monday; break; }
      case 3: { this._dayOfWeek = DaysOfWeek.tuesday; break; }
      case 4: { this._dayOfWeek = DaysOfWeek.wednesday; break; }
      case 5: { this._dayOfWeek = DaysOfWeek.thursday; break; }
      case 6: { this._dayOfWeek = DaysOfWeek.friday; break; }
      default: { this._dayOfWeek = DaysOfWeek.saturday; }
    }

  }

  private static dateDefinitionToNativeDateObject(rawDateTime: Readonly<DateWithoutTime.DateDefinition>): Date {
    return new Date(
      rawDateTime.year,
      ((): number => {

        if ("monthName" in rawDateTime) {
          return getMonthNumberByName({
            targetMonthName: rawDateTime.monthName,
            numerationFrom: 0
          });
        }

        return "monthNumber__numerationFrom1" in rawDateTime ?
            rawDateTime.monthNumber__numerationFrom1 - 1 : rawDateTime.monthNumber__numerationFrom0;

      })(),
      rawDateTime.dayOfMonth
    );
  }

}

namespace DateWithoutTime {

  export type DateDefinition =
    {
      year: number;
      dayOfMonth: number;
    } &
    (
      { monthName: MonthsNames; } |
      { monthNumber__numerationFrom0: number; } |
      { monthNumber__numerationFrom1: number; }
    );

}
soat7uwm

soat7uwm1#

我们能不能写

this.state.dateWithoutTimeInstance.shiftBySpecificDaysCount({
 daysCount: 5,
 toFuture: true
});

in React?

不行(或者说,您可以 * 编写 * 它,但它不会正确工作)。React状态成员必须被视为不可变的。

不要直接修改状态

例如,这不会重新呈现组件:

// Wrong
this.state.comment = 'Hello';

请改用setState()

// Correct
this.setState({comment: 'Hello'});

(And您需要用一个具有更新状态的新示例来 * 替换 * 状态成员。
下面是一个改变状态对象的示例。注意,组件不会重新呈现:
第一个
以下是正确的写法(只是为了清楚起见,比通常的写法更加冗长):
一个

相关问题