Closed11
動的にatomを増やしたい
ざっくりいうとTODOリストの各アイテムをatomで管理したいみたいなイメージ。なのでそれでプロトタイプをやるか。
なんで各アイテムをatomで管理したいかと言うと、バリデーションとかやるときにそっちのほうが便利なんじゃない?っていう発想
これを使う。TODOリストの例も載ってるけど編集機能がほしい。
とりあえずこういう感じ
export type Todo = {
id: string;
title: string;
checked: boolean;
};
export const todoFamily = atomFamily(
(param: Todo) => atom(param),
(a, b) => a.id === b.id
);
リストで表示するために別途idの配列を管理するatomが必要だな?
こういうことかと思ったんだけど違うっぽい。
ふつうにできた。↑は作ったidをtodoIdsAtomに入れるの忘れてただけ
import { atom } from "jotai";
import { atomFamily } from "jotai/utils";
import { Todo } from "./type";
export const todoFamily = atomFamily(
(param: Todo) => atom(param),
(a, b) => a.id === b.id
);
export const todoIdsAtom = atom<string[]>([]);
export const todosAtom = atom<Todo[]>((get) => {
const todoIds = get(todoIdsAtom);
const todos = todoIds.map((id) =>
get(
todoFamily({
id,
// idで検査するため、下記は型合わせのための適当な値
title: "",
checked: false,
})
)
);
return todos;
});
todosAtomを作らなくても、todoIdsでmapして各item内で値を取って来ればいいか。
{ids.length !== 0 && (
<ul>
{ids.map((id) => (
<TodoItem key={id} id={id} />
))}
</ul>
)}
const TodoItem: FC<{ id: string }> = ({ id }) => {
const [todo, setTodo] = useAtom(
todoFamily({ id, title: "", checked: false })
);
return <li key={todo.id}>{todo.title}</li>;
};
bottom upという考え方を念頭に置くと2つ目のほうがそれっぽい気がする。
うん、こういう要領で各アイテムを編集できることを確認した
const TodoItem: FC<{ id: string }> = ({ id }) => {
const [todo, setTodo] = useAtom(
todoFamily({
id,
// idで検査するため、下記は型合わせのための適当な値
title: "",
checked: false,
})
);
const [editMode, setMode] = useState(false);
const toggle = () => setTodo((prev) => ({ ...prev, checked: !prev.checked }));
const edit = (text: string) => setTodo((prev) => ({ ...prev, title: text }));
const onChange: ChangeEventHandler<HTMLInputElement> = (e) =>
edit(e.target.value);
return (
<li key={todo.id} className="flex items-center gap-10">
<Button onClick={() => setMode((mode) => !mode)}>
{editMode ? "終了" : "編集"}
</Button>
<div className="flex items-center gap-2">
<input
id={todo.id}
type="checkbox"
checked={todo.checked}
onChange={toggle}
/>
{editMode ? (
<Input value={todo.title} onChange={onChange} className="w-80" />
) : (
<Label htmlFor={todo.id} className="px-3">
{todo.title}
</Label>
)}
</div>
</li>
);
};
配列でTodoを持って各アイテムを編集しようと思うと、filterとかが必要なのでこっちのほうが便利だと思った。
しかし二重stateっぽいのは否めない。
あーなんか似たようなことをやってる人がいた
このスクラップは2023/08/14にクローズされました