开发DateWithoutTime工具类,是否需为React提供不可变API?
关于React中使用可变
DateWithoutTime类的疑问 背景
我正在开发DateWithoutTime类,它的公有方法会直接修改类的私有字段,示例调用代码如下:
this.state.dateWithoutTimeInstance.shiftBySpecificDaysCount({ daysCount: 5, toFuture: true });
类的完整代码见附录,此处省略部分内容。
在React这类框架中,禁止直接修改state中的对象。我自己的解决方案是基于旧实例创建新实例后再修改,示例代码如下:
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 }; });
问题
请问在React中能否直接使用以下代码?
this.state.dateWithoutTimeInstance.shiftBySpecificDaysCount({ daysCount: 5, toFuture: true });
如果不能,是否需要为DateWithoutTime类提供不可变更新方法?比如类似下面的实现:
this.setState((state) => { return { // 返回新实例 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; } // 其他getter方法... 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; } ); }
内容的提问来源于stack exchange,提问作者Takeshi Tokugawa YD
相关产品推荐
相关产品推荐

