好友
阅读权限10
听众
最后登录1970-1-1
|
最近在整理一个图片处理表单:模型、模式、输入图片数量、宽高比和分辨率不是互相独立的。后端返回的能力配置会变化,用户切换模型后,旧模式可能失效;模式变化后,允许的图片数量和输出规格又会跟着变。
最初我给每个下拉框各写一个 useEffect,结果容易出现连锁更新、短暂非法组合,甚至把旧状态提交出去。后来改成一次按依赖顺序做纯函数收敛:模型 → 模式 → 图片数量 → 宽高比 → 分辨率。
[code=typescript]
type Mode = "single_edit" | "multi_fusion";
type Variant = {
mode: Mode;
minSources: number;
maxSources: number;
ratios: string[];
resolutions: string[];
};
type ModelCapability = {
id: string;
enabled: boolean;
variants: Variant[];
};
type FormState = {
modelId: string;
mode: Mode;
sourceIds: string[];
ratio: string;
resolution: string | null;
};
function reconcile(
current: FormState,
models: ModelCapability[],
): { state: FormState; issues: string[] } {
const available = models.filter((item) => item.enabled);
if (!available.length) throw new Error("no_available_model");
const model =
available.find((item) => item.id === current.modelId) ?? available[0];
const variant =
model.variants.find((item) => item.mode === current.mode) ??
model.variants[0];
if (!variant) throw new Error("no_available_mode");
const sourceIds = current.sourceIds.slice(0, variant.maxSources);
const ratio = variant.ratios.includes(current.ratio)
? current.ratio
: variant.ratios[0];
const resolution = variant.resolutions.length === 0
? null
: variant.resolutions.includes(current.resolution ?? "")
? current.resolution
: variant.resolutions[0];
const issues: string[] = [];
if (sourceIds.length < variant.minSources) {
issues.push(至少需要 ${variant.minSources} 张输入图片);
}
if (!ratio) issues.push("当前组合没有可用宽高比");
return {
state: {
modelId: model.id,
mode: variant.mode,
sourceIds,
ratio: ratio ?? "",
resolution,
},
issues,
};
}
[/code]
这里没有为了满足最小图片数自动复制输入,只会截掉超过上限的图片;不足下限时保留用户已有输入并返回错误,让界面明确提示补充。分辨率列表为空则写成 null,避免把上一个模型的分辨率偷偷带过去。
提交时我还会把 capabilityVersion 和收敛后的状态一起形成不可变快照。服务端按当前版本再次校验;如果版本已经变化,就返回字段级错误并要求前端重新拉取能力配置,不能相信前端已经收敛过。
现在比较纠结两个点:
1. 自动回退到第一个合法选项时,是否应该逐字段提示“原选择已失效”,还是只在最终组合变化较大时统一提示?
2. 能力版本过期后,应该尽量保留仍合法的选择,还是直接重置整个表单,减少状态歧义? |
|
发帖前要善用【论坛搜索】功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。 |
|
|
|
|
|