Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Jotaiで作ったフォームをApollo_Clientで投げたらいい感じだった件.pdf

 Jotaiで作ったフォームをApollo_Clientで投げたらいい感じだった件.pdf

asazu taiga

March 21, 2023
Tweet

More Decks by asazu taiga

Other Decks in Technology

Transcript

  1. 自己紹介 • Asazu Taiga • twitter ◦ @AsazuTaiga • 所属

    ◦ 株式会社JADE • 最近好きなもの ◦ VTuberの音楽 ◦ ボイロキッチン動画 ▪ (自炊しないのに)
  2. Agenda • Jotaiの紹介 • Apollo Clientの紹介 • GraphQL Code Generatorの紹介

    • Jotaiを使ったフォームの作成 • デモ • ちょっといい感じポイント • ちょっとどうかなポイント • まとめ • 質疑応答
  3. Jotai サンプル(公式から引用) import { atom, useAtom } from 'jotai' //

    Create your atoms and derivatives const textAtom = atom('hello') const uppercaseAtom = atom( (get) => get(textAtom).toUpperCase() ) // Use them anywhere in your app const Input = () => { const [text, setText] = useAtom(textAtom) const handleChange = (e) => setText(e.target.value) return ( <input value={text} onChange={handleChange} /> ) }
  4. Jotai サンプル(公式から引用) const Uppercase = () => { const [uppercase]

    = useAtom(uppercaseAtom) return ( <div>Uppercase: {uppercase}</div> ) } // Now you have the components const App = () => { return ( <> <Input /> <Uppercase /> </> ) }
  5. Apollo Client サンプル(公式から引用、一部略) function DisplayLocations() { const { loading, error,

    data } = useQuery(GET_LOCATIONS); if (loading) return <p>Loading...</p>; if (error) return <p>Error : {error.message}</p>; return data.locations.map(({ id, name, description, photo }) => ( <div key={id}>(中略...)</div> )); }
  6. Jotaiを使ったフォームの作成 - nameフィールドの例 // エラーメッセージを表示するかどうかを判定するためのatom(フォーム全体で共有) const shouldShowErrorMessageAtom = atom(false); const

    nameAtom = atom(""); const nameSchema = z .string() .min(3, "名前は3文字以上で入力してください") .max(20, "名前は20文字以内で入力してください");
  7. Jotaiを使ったフォームの作成 - nameフィールドの例 const nameErrorAtom = atom((get) => { const

    name = get(nameAtom); const result = nameSchema.safeParse(name); if (result.success) { return ""; } return result.error.issues[0].message; }); const nameDisplayErrorAtom = atom((get) => { const shouldShow = get(shouldShowErrorMessageAtom); const error = get(nameErrorAtom); return shouldShow ? error : ""; }); export const useName = () => { const [value, setValue] = useAtom(nameAtom); const errorMessage = useAtomValue(nameDisplayErrorAtom); return { value, setValue, errorMessage }; };
  8. クロスフィールドバリデーションが書きやすい const passwordErrorAtom = atom((get) => { const password =

    get(passwordAtom); // example: cross field validation // 実際こんなことはしないと思うが、例として const name = get(nameAtom); if (name === password) { return "名前とパスワードは異なるものにしてください "; } return ""; });
  9. 利用側のコードがシンプルになる const NameInput = () => { const { value,

    setValue, errorMessage } = useName(); return ( <FormControl error={!!errorMessage}> <TextField label="Name" value={value} onChange={(e) => setValue(e.target.value)} /> <FormHelperText>{errorMessage}</FormHelperText> </FormControl> ); }; const InputView = () => { return ( <Stack gap={2} component="form" onSubmit={(e) => e.preventDefault()}> <NameInput /> <EmailInput /> <PasswordInput /> <Stack direction="row" gap={2}> <ResetButton /> <NextButton /> </Stack> </Stack> ); };
  10. フィールドが増えた際に依存フィールドの修正もれそう // フォームの入力値をリセットするためのatom const resetFormAtom = atom(null, (get, set) =>

    { set(nameAtom, ""); set(emailAtom, ""); set(passwordAtom, ""); set(shouldShowErrorMessageAtom, false); }); addressが増えたら ここに足す...
  11. フィールドが増えた際に依存フィールドの修正もれそう // フォーム全体をまたいで、エラーがあるかかないかを判定するためのatom const hasErrorAtom = atom((get) => { const

    nameError = get(nameErrorAtom); const emailError = get(emailErrorAtom); const passwordError = get(passwordErrorAtom); return nameError || emailError || passwordError; }); ここもやんけ...