typescript 如何重构共享几乎相同逻辑的两个React组件?

aor9mmx1  于 2023-03-04  发布在  TypeScript
关注(0)|答案(1)|浏览(130)

我尝试重构两个组件DateTimeFormFieldTimeFormField,因为这两个组件共享几乎相同的逻辑和输出。
我想到的一种方法是导出功能组件DateTimeFormField中的函数,但这似乎不是一个干净的解决方案,因为两个组件(声明的变量)之间仍然存在相同的逻辑。
从一些研究来看,自定义钩子似乎可以解决这里的代码重复问题,但两个组件都是无状态的,所以我不完全确定自定义钩子是否会对我的情况造成过度影响。
DateTimeFormField.tsx

function DateTimeFormField({
    fieldName,
    flatFieldName,
    validationMessage,
    value,
    onChange,
    onBlur
}: FieldProps) {
    const valueAsStr = value === undefined ?
        "" :
        value as string;
    const dateFromValue = valueAsStr.substring(0, 10);
    const timeFromValue = valueAsStr.substring(11, 16);

    const todayDateObj = new Date();
    const todayDate = todayDateObj.toISOString().slice(0, 10);

    function onDateChange(dateUpdate: string) {
        const date = dateUpdate || "0000-00-00";
        const time = timeFromValue || "00:00";

        return onChange(flatFieldName, date + "T" + time + ":00+00:00");
    }

    function onTimeChange(timeUpdate: string) {
        const date = dateFromValue || todayDate;
        const time = timeUpdate || "00:00";

        return onChange(flatFieldName, date + "T" + time + ":00+00:00");
    }

    function onTimeBlur(timeUpdate: string, fieldName: string) {
        onTimeChange(timeUpdate);
        onBlur(fieldName);
    }

    return (
        <FormGroup
            validationMessage={validationMessage}
            data-element="date-time-form-field-form-group">
            <FieldLabel fieldName={fieldName} />
            <div className="date-time-combo">
                <DatePicker
                    inputProps={{"data-element": "date-form-field-input"}}
                    dateFormat="YYYY-MM-DD"
                    initialValue={dateFromValue}
                    onChange={(date) => onDateChange(date.isoFormattedDate)}
                    onBlur={() => onBlur(flatFieldName)}
                />
                <TimePicker
                    data-element="time-form-field-input"
                    timeFormat="HH:mm"
                    initialValue={timeFromValue}
                    onSelect={(time) => onTimeChange(time.rawValue)}
                    onBlur={(time) => onTimeBlur(time.rawValue, flatFieldName)}
                />
            </div>
        </FormGroup>
    );
}

export default memo(DateTimeFormField);

TimeFormField.tsx

function TimeFormField({
    fieldName,
    flatFieldName,
    validationMessage,
    value,
    onChange,
    onBlur
}: FieldProps) {
    const valueAsStr = value === undefined ?
        "" :
        value as string;
    const dateFromValue = valueAsStr.substring(0, 10);
    const timeFromValue = valueAsStr.substring(11, 16);

    const todayDateObj = new Date();
    const todayDate = todayDateObj.toISOString().slice(0, 10);

    function onTimeChange(timeUpdate: string) {
        const date = dateFromValue || todayDate;
        const time = timeUpdate || "00:00";

        return onChange(flatFieldName, date + "T" + time + ":00+00:00");
    }

    function onTimeBlur(timeUpdate: string, fieldName: string) {
        onTimeChange(timeUpdate);
        onBlur(fieldName);
    }

    return (
        <FormGroup
            validationMessage={validationMessage}
            data-element="time-form-field-form-group">
            <FieldLabel fieldName={fieldName} />
            <div className="time-combo">
                <TimePicker
                    data-element="time-form-field-input"
                    timeFormat="HH:mm"
                    initialValue={timeFromValue}
                    onSelect={(time) => onTimeChange(time.rawValue)}
                    onBlur={(time) => onTimeBlur(time.rawValue, flatFieldName)}
                />
            </div>
        </FormGroup>
    );
}

export default memo(TimeFormField);
nlejzf6q

nlejzf6q1#

您可以添加一个属性来指定是否要选择日期。然后您可以基于该属性有条件地呈现。
一般形式是

if (/* some condition based on the props*/) {
    return (
        <> something </>
    );
} else {
    return (
        <> something else </>
    );
}

但是,您也可以将条件部分嵌入到单个return语句中。
例如,如果将includeDate: boolean添加到DateTimeFormField组件中的props,则可以渲染以下内容:

const dataElement = `${includeDate ? "date-" : ""}time-form-field-form-group`;
const divClass = `${includeDate ? "date-" : ""}time-combo`;

return (
    <FormGroup
        validationMessage={validationMessage}
        data-element={dataElement}
    >
        <FieldLabel fieldName={fieldName} />
        <div className={divClass}>
            { includeDate ? (
                <DatePicker
                    inputProps={{"data-element": "date-form-field-input"}}
                    dateFormat="YYYY-MM-DD"
                    initialValue={dateFromValue}
                    onChange={(date) => onDateChange(date.isoFormattedDate)}
                    onBlur={() => onBlur(flatFieldName)}
                />
            ) : null }
            <TimePicker
                data-element="time-form-field-input"
                timeFormat="HH:mm"
                initialValue={timeFromValue}
                onSelect={(time) => onTimeChange(time.rawValue)}
                onBlur={(time) => onTimeBlur(time.rawValue, flatFieldName)}
            />
        </div>
    </FormGroup>
);

所以你只需要一个组件,然后根据 prop 渲染你想要渲染的东西。

相关问题