LoginSignup
2
1

More than 1 year has passed since last update.

[Async Iteretor]ちょっとずつ変化するコンポーネントを作りたい

Last updated at Posted at 2021-06-06

はじめに

1 秒ごとに処理に応じてちょっとずつ変化していくコンポーネントが作りたかった です

プログレスバーの拡張版みたいな...

setInterval を使って実装して見たけど、setInterval の引数に渡した関数内では State が参照できないようで、以下のように setState 内で無理矢理条件分岐を作らないといけないです

const intervalValue = setInterval(() => {
  setCount((count) => {
    if (count === 5) {
      clearInterval(intervalValue)
      return count
    }
    return count + 1
  })
}, 1000)

もっといい方法はないか考えていたらふと Generator の事を思い出したので実装してみることにしました

実装

お試しなのでシンプルにカウントアップするものを実装

作るもの

  • ボタンを押すと 1 秒おきにカウントアップされる
  • 比較のため Genetretor+Iteretor を使ったものと Interval を使ったものどっちも実装してみる

コード

See the Pen poeVOGB by あずは (@azuha) on CodePen.

解説

非同期ジェネレータ関数を利用して、count が 5 になるまで 1 秒毎に yield でカウントアップしていきます

ジェネレータ関数を利用するとその戻り値は Generetor 型となり、yield で指定した値を持つ、いわゆるイテラブルなオブジェクトとして返却されます

wait 関数を自作し、await で待機処理を作るために async 関数にしています

const countUp = async function* (first) {
  let count = first;
  while(count < 5) {
    await wait(1000)
    count++
    yield count
  }
}

非同期ジェネレータ関数の戻り値は AsyncGeneretor 型となり、受け取ったイテラブルなオブジェクトは for await...of 文で取り出すことができます。

for await (const value of countUp(0)) {
  setCount(value)
}

ES2018 まで for 文の中で非同期処理は行えなかったみたいですが、for await...of 文が追加されてからは上記のような書き方ができるようになりました

Interval を使用する場合 setInterval の戻り値を保持する State を用意しないといけなかった反面、ジェネレータ関数を利用すると State は必要なく簡潔に書けることがわかると思います

後書き

今まであまり触れてこなかったジェネレータ関数を利用することで欲しかった「ちょっとずつ変化していくコンポーネント」を実装することができました

割と最近出た構文(だと思っている)ですが、こういう新しい技術は覚えておくと今まで難しかったことがあっさり解決することがあるんだな〜と勉強になりました

2
1
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
2
1