さしぐめのブログ

Web / Meme / 海外アニメコミュニティ等の雑記。IDがモンテネグロドメインを内包してるって最高。

Reactで進捗カウントダウンを"分割"しようとして算数力の無さに苦しむ

まず、これは算数が全然できない人が、プログレスバーの実装で四苦八苦する話であるから、つよつよプログラマーの方は読まなくてよろしい。

どういう状況か

以下の要件を満たすコンポーネントを作っている。

  • 指定した秒数をカウントダウン
  • かつ、指定した文字列の配列のlengthの分だけだけ「分割」する
  • 文字はスライドショー的に切り替えて、プログレスバーも用意

例えば、「30秒数える間に、"開始しました"、"処理中です"、"終わりました"が均等に切り替わる」という感じだ、

なぜ必要か

asobinon.org

アソビノンというサイトを作っているんだが、「ビジュアルエディタで編集する」機能をつけたものの、Vercelは即時反映されないことを編集者に明示する必要があった。

しかし、Vercelでのデプロイ状況を随時確認することは、GitHubのAPIを使っても難しいというか、適切な通知の受け取り方がわからない。

そこで、「偽のロード画面」を作ることにした。

2021/05/28現在の成果

2021/05/28の成果

youtu.be

プログレスバーはChakra UIを使っている。めちゃくちゃ助かる。

import { Box, Progress, Stack, Stat, StatHelpText, StatNumber } from '@chakra-ui/react';
import { useEffect, useState } from 'react';

const SlideShow = ({ initialCount, contents }: { initialCount: number; contents: string[] }) => {
  // progressがsplitになるまでカウントダウン
  const split = contents.length - 1;
  const [count, setCount] = useState(initialCount);
  const [progress, setProgress] = useState(0);
  useEffect(() => {
    count > 0 &&
      setTimeout(() => {
        setCount(count - 1);
      }, 1000);
    // あまりを使って進捗を分割
    // この計算がマジでわからない
    // 手探り
    if (count % ((initialCount + 1) / split) < 1) setProgress(progress + 1);
    count == 0 && setProgress(split);
  }, [count]);

  return (
    <Stack spacing={6}>
      <Box>変更の反映には{initialCount}秒ほど時間がかかります</Box>
      <Stat>
        <StatNumber>{count}</StatNumber>
        <StatHelpText>数字は目安です</StatHelpText>
      </Stat>
      <Progress
        size="lg"
        hasStripe={count > 0}
        isAnimated={count > 0}
        value={progress}
        max={split}
      />
      <Box>
        {contents.slice(0, progress + 1).map((c, n) => (
          <Box key={n}>{c}</Box>
        ))}
      </Box>
    </Stack>
  );
};

export default SlideShow;

count % ((initialCount + 1) / split) < 1が、正しい「割った時にあまり一未満ならプログレスを増やす」という考えでやったが、文字数配列のlengthと秒数によっては、これでいまくカウントダウンできなかった、

initialCount + 1というのも、おまじないのようにつけたら動いちゃっただけで、実際の正解はわからない。

 <SlideShow
            initialCount={45}
            contents={[
              '更新開始...',
              'GitHubからサーバーへ転送中...',
              'サーバーが読み取り中...',
              'パッケージをインストール中...',
              '構文をチェック中...',
              '(ここでHTMLがおかしいと止まります)',
              '(HTMLがOKなら)ビルド完了...',
              '(HTMLがOKなら)デプロイ中...',
              '(HTMLがOKなら)DONE!',
            ]}
          />

ちなみに呼び出しはこう。割と需要はあると思います。

Copyright © 2021 Ryo Ando. Built w/ Love & Hatena Blog.