10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

SvelteでReactのCustom Hooksみたいなことをしたい

Last updated at Posted at 2021-07-01

TL;DR

svelte/storeを使いましょう。

はじめに

カスタムフックは次のようなやつです。

カスタムフックの例(React)
// カスタムフックの定義
const useCounter = () => {
  const [count, setCount] = useCounter(0)
  const increment = () => setCount(prev => prev + 1)
  return { count, increment }
}

// 使う側
const App = () => {
  const { count, increment } = useCounter()

  return (
    <>
      <span>{count}</span>
      <button onClick={increment}>+1</button>
   </>
  )
}

(シンプルさを求めて簡略化しています。実際はuseCallbackを使うかなどを考える必要があると思います。)
カスタムフックにより、ステートとロジックを外部に切り出して再利用可能にしたり、複雑なロジックを隠蔽して見通しを良くしたりすることができます。

これを、Svelteでもやりたい。VueだとCompositionAPIでカスタムフックを実現できるますが、Svelteではどうでしょうか。

普通に書いてみると(うまく行かない例)

SvelteではReactでいうステートを表現するのにletを使います

svelte
<script>
  let count = 0
</script>

これを外部のファイルに切り出して見ましょう。

外部のjsファイル
export const useCounter = () => {
  let count = 0
  const increment = () => count++
  return { count, increment }
}

svelteファイルで使ってみます。

svelteファイル
<script>
  import { useCounter } from './counter'

  const { count, increment } = useCounter()
</script>

<span>{count}</span>
<button on:click={increment}>+1</button>

実行結果
Kapture 2021-07-01 at 21.15.26.gif
カウントが全く増えません。
svelteファイルのscript部分でletを使えばリアクティブな値になりますが、外部のjsファイルでletで宣言してもただの変数です。

外部に切り出せるものといえば、、、

Svelteで外部に切り出せる、リアクティブな値といえば標準搭載されているstoreです。
storeを使えば、以下のように動作させることができます。

外部のjsファイル
import { writable } from 'svelte/store'

export const useCounter = () => {
  const { subscribe, update } = writable(0)
  const increment = () => update(prev => prev + 1)
  return { count: { subscribe }, increment }
}
svelteファイル
<script>
  import { useCounter } from './counter'

  const { count, increment } = useCounter()
</script>

<span>{$count}</span>
<button on:click={increment}>+1</button>

こちらで試せます。(REPLで共有しやすいのもsvelteの良いところ)
https://svelte.dev/repl/7580c4426c1947d8aa3d149a05bdc895?version=3.38.3

Kapture 2021-07-01 at 21.27.39.gif

svelteファイル内で使うときは、$countと$マークを付ける必要があることに注意しましょう。
また、subscribeの挙動がわからない場合は、公式ドキュメントのcustom-storeの章を読みましょう。

ちなみに、このようにsvelte/storeを使って外部にリアクティブな値を切り出しているSvelteライブラリも多いです。
フォームライブラリの feltesvelte-use-formなどが一例です。

あとがき

Svelteでカスタムフックを使いたくなったらstoreを使うのが一つの方法です。
つまるところ、SvelteのstoreはReduxやVuexのストアみたいなグローバルステート以外の役割も持っているということです。
ということもあり、筆者はSvelteのstoreをグローバルステートとして使う場合は~Storeもしくは~Stateなどの命名するのが良いと考えています。こうすることで、カスタムフックで使うstore(グローバルステートではない)と区別しやすくなるはずです。

10
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?