Open4
FEのDDDやりたい

FEでDDDやりたいので、アイデアが欲しい。
ざっくり、MVVMを基本にVM層をapplicationと捉えてdomain layerにする感じ、、、

やりたいこととしては、最近FEのライブラリ依存が非常に高く抜け出したい。
具体で言うと、実装をしたい→どのライブラリを使うか調査になってしまっている。理想の状態を定義してからライブラリは参考程度・もしくはドンピシャで合うものがあれば使うくらいにしたい。

そもそもstateを使わなくても実装できる機能を使う前提で組み立ててしまうことを辞めたい

これはどっちがいいのか
stateで管理する
import { useCallback, useState } from "react";
function MyForm() {
const [value, setValue] = useState("");
const [error, setError] = useState("");
// バリデーション関数を Memoize(入力値依存で再生成)
const validate = useCallback((val: string) => {
if (val.length < 5) return "5文字以上入力してください";
return "";
}, []);
const handleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const val = e.target.value;
setValue(val);
setError(validate(val));
};
return (
<div>
<input value={value} onChange={handleChange} aria-invalid={!!error} />
{error && <p role="alert">{error}</p>}
</div>
);
}
export default MyForm;
onInput等で毎回validateする
import { useRef } from "react";
function MyForm() {
const inputRef = useRef<HTMLInputElement>(null);
const handleChange = () => {
const input = inputRef.current;
if (!input) return;
if (input.value.length < 5)
input.setCustomValidity("5文字以上入力してください");
else input.setCustomValidity("");
input.reportValidity();
};
return (
<div>
<input ref={inputRef} onInput={handleChange} required minLength={5} />
</div>
);
}
export default MyForm;
onsubmitでvalidity
import { useRef } from "react";
import { z } from "zod";
const getInputElement = (
form: HTMLFormElement,
name: string
): HTMLInputElement => {
const found = form.querySelector(`input[name="${name}"]`);
if (!(found instanceof HTMLInputElement))
throw new Error(`Input element with name ${name} not found`);
return found;
};
type IValidate = {
customValidity: (v: string) => void;
value: unknown;
schema: z.ZodSchema;
};
const validate = (input: IValidate): void => {
const result = input.schema.safeParse(input.value);
if (!result.success) {
input.customValidity(result.error.errors.map((e) => e.message).join("\n"));
} else {
input.customValidity("");
}
};
const validateAll = (inputs: IValidate[]): void => {
inputs.forEach(validate);
};
function MyForm() {
const formRef = useRef<HTMLFormElement>(null);
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
const form = e.currentTarget;
validateAll([
{
customValidity: (v: string) =>
getInputElement(form, "username").setCustomValidity(v),
value: getInputElement(form, "username").value,
schema: z.string().min(5, "5文字以上で入力してください"),
},
]);
// ブラウザ組み込みのチェック
if (!form.checkValidity()) {
// ここで不正なフィールドにフォーカスが移り、tool-tip風のメッセージが出る
form.reportValidity();
return;
}
};
return (
<form ref={formRef} onSubmit={handleSubmit} noValidate>
<div>
<label>
名前(5文字以上):
<input name="username" type="text" required minLength={5} />
</label>
</div>
<div>
<label>
年齢(正の整数):
<input name="age" type="number" required min={1} />
</label>
</div>
<button type="submit">送信</button>
</form>
);
}
export default MyForm;