2020-09-23に投稿

Recoilの書き方はこんな感じかなというイメージ

主に細かいコンポーネントをいくつも作って開発するようなプロジェクトを進め始めたので、丁度マッチしているかなと思いReduxを使い始めていたのをやめてRecoilを使ってみました。

書いているうちにRecoilがこの仕様であればだいたいこんな感じに使っていくことになるのかな……と思ったのでなんとなく書いていきます。

まず基本的なステートの定義は下記のようです。

const textState = atom({
  key: 'textState',
  default: '',
})

key-valueのハッシュみたいなもので、keyに対して値を保存するような非常にシンプルなイメージです。

これを実際に使うとなるとこのatomなどをたくさん定義していくわけですが、基本的にRecoilが必要な場面となるとその値をコンポーネントにまたがって使用したい時になると思います。そうすると複数のコンポーネントで毎回文字列でキーを指定してステートを利用していくというのはあまり望ましくないと思います。変更にも弱いですし、単なる書き間違えも発生します。

ということで、下記のどちらかのパターンになるのではないかと思います。

  • カスタムフックでまとめる
  • 定義を個別のファイルで行う

後者でも良いのですが、一つ二つしか値を使わない、というパターンもそんなになさそうに思いますのでだいたいカスタムフックでまとめる形がよくある形になるのでは、という気がしています。

カスタムフックのパターン

例えばカスタムフックの場合はこんな感じです。

import { atom, useRecoilState } from 'recoil'
import { Post, createEmptyPost } from '@/models/Post'

export type Mode = 'input' | 'confirm' | 'completed'

const modeState = atom<Mode>({
  key: 'post/form/mode',
  default: 'input'
})

const postState = atom<Post>({
  key: 'post/form/post',
  default: createEmtpyPost()
})

const fileState = atom<File | null>({
  key: 'post/form/file',
  default: null
})

export default function usePostForm() {
  const [mode, setMode] = useRecoilState(modeState)
  const [post, setPost] = useRecoilState(postState)
  const [file, setFile] = useRecoilState(fileState)

  return {
    mode,
    setMode,
    post,
    setPost,
    file,
    setFile,
  }
}

実際にコンポーネント上で使う時は下記のような感じです。

export default function MyComponent() {
  const { mode, post, setPost } = usePostForm()

  return (
    <div>
      {mode === 'input' ? (
        <input type="text" value={post.title} onChange={(e) => setPost({ ...post, title: e.target.value })} />
      ) : (
        <span>{post.title}</span>
      )}
    </div>
  )
}

どのコンポーネントでも同様の使い方ができますので細分化も苦にならず、シンプルに使うことができます。キーを何度も入力する必要もありません。というか、結局ReduxのStoreを定義しているようなイメージになってきますね。書き方はそれよりは簡単ですが。まあ結局どういい感じに管理するかを考えると何を使うにしろ似てくるのかもしれません。

個別に定義するパターン

さっきの例でいうと、

export type Mode = 'input' | 'confirm' | 'completed'

export const modeState = atom<Mode>({
  key: 'post/form/mode',
  default: 'input'
})

のような定義をそれぞれファイルとして作り、使用する場合は

import { modeState } from '../hooks/mode_state'

export default function MyComponent() {
  const [mode, setMode] = useRecoilState(modeState)
  :
}

という感じになると思います。これもまあ間違いは少なくて良いと思いますが、アプリケーション全体で単独で使い回すという目的が大きくなってくると思いますので、あまり利用するパターンは多くなさそうな気もします。ちょっと処理が増えるとカスタムフックにしちゃえばいいか、となってしまうと思いますし。

まとめ

雑に使おうと思えば使えますが、やはり使い方をある程度決めてまとめた方があとあと困らないかなという気がします。シンプルに使えるライブラリですが、開発が進むにつれて一体どのキーがどう使われているのか、使われているのか分からなくなってしまってぐちゃぐちゃになってしまう状況をなるべく避けるように使って行ったほうが良さそうに思いました。

ツイッターでシェア
みんなに共有、忘れないようにメモ

だら@Crieit開発者

Crieitの開発者です。 Webエンジニアです(在宅)。大体10年ちょい。 記事でわかりにくいところがあればDMで質問していただくか、案件発注してください。 業務依頼、同業種の方からのコンタクトなどお気軽にご連絡ください。 業務経験有:PHP, MySQL, Laravel, Vue.js, React, Node, RoR 趣味:Elixir, Phoenix, Nuxt, Express, GCP, AWS等色々 PHPフレームワークちいたんの作者

Crieitは誰でも投稿できるサービスです。 是非記事の投稿をお願いします。どんな軽い内容でも投稿できます。

また、「こんな記事が読みたいけど見つからない!」という方は是非記事投稿リクエストボードへ!

有料記事を販売できるようになりました!

こじんまりと作業ログやメモ、進捗を書き残しておきたい方はボード機能をご利用ください。
ボードとは?

コメント