Refactor Doc
使用 zod 替 response 跟 request body 以及 form schema
export const usageScenarioRequestBodySchema = z.object({
name: z.string(),
emissionClassification: z.nativeEnum(EMISSION_CLASSIFICATION).optional(),
// ...
});
export const usageScenarioFormSchema = z.object({
name: z.string(),
emissionClassification: z.nativeEnum(EMISSION_CLASSIFICATION).optional(),
// ...
});
export interface UsageScenarioDetail extends UsageScenarioRequestBody {
id: string;
}
// src/modules/ProductSeries/domain/UsageScenario/UsageScenario.ts-
欄位的 name 可以不用照著 api 對應的 key 命名
-
以
UI上的角度提供覺得最適合的欄位 name
統一地方處理 convert
-
避免 reuse component 時需要各別為了不同 API 做做欄位的判斷跟調整
-
減少後端格式調整時,必須修改分散邏輯的困擾
-
可在轉換階段將數據格式轉換為更適合前端使用的格式
-
解耦 API 與元件之間的關係
function convertFromDataToRequest(formData: UsageScenarioForm): UsageScenarioRequestBody {}
function convertResponseToFormData(response: UsageScenarioDetail): UsageScenarioForm {}使用 zod 定義的 form schema 做 form validate
所有驗證相關的工作均在 resolver 的 callback 中完成
const methods = useForm({
resolver: async (values, context, options) => {
if (values.metadata.relevance !== EmissionSourceRelevance.REL_TRUE) {
return { errors: {}, values };
}
if (values.factors[0].type === EmissionSourceFactorType.DEFAULT) {
return await zodResolver(
settingRelevanceSchema.merge(z.object({ documents: z.array(documentSchema).optional() })),
)(values, context, options);
}
return await zodResolver(settingRelevanceSchema)(values, context, options);
},
});
// src/app/[lng]/org-cfv/[projectId]/emission-sources/relevant/components/SettingRelevanceModal.tsxform 的共用
-
小部分的共用欄位可以共用,但是提供 prefix 來處理可能在 form 中 name 一樣的問題
type Props = { prefix?: string; }; export const UnitFields = ({ prefix = 'default' }: Props) => { return ( <> <input name={`${prefix}.unitType`} /> <input name={`${prefix}.unit`} /> </> ); }; -
大型表單應分開並確實為每個大型表單定義 Schema
// emission cat1.1 const methods = useForm<Emission1_1Schema>() // emission cat1.2 const methods = useForm<Emission1_2Schema>()