3
1

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 1 year has passed since last update.

スーパーでの「来週なにつくる?」に答えを出すツールをReactで作った

Last updated at Posted at 2022-03-06

なぜ作ったか

週1回の買い物時にできるだけ必要なものは買い揃えたい。
そのために何を作るか決める必要があるが、大体スーパーについてから考えてしまうのである程度自動化したい。

メイン機能

準備したリストの中からランダムな重複なしリストを取得するアプリケーション

入力

結果取得

工夫点

  • 1アイテムだけチェンジする機能 -> 最近作った、材料がないなどでチェンジするための機能。全部チェンジするとなかなか理想の結果が得られないことがある。
  • 結果をLINEに出力するボタン(SHARE BY LINE ) -> 結果の永続化、シェア
  • 入力したリストはブラウザに保存 -> 入力時間削減

LINEシェア結果

利用技術

  • 言語: TypeScript
  • フレームワーク: Next.js
  • UI: MUI
  • CD: github actionsでGithub Pagesにdeploy

ソースコードと主要部分の実装

リポジトリ: https://github.com/yoshikipom/dinnerslot-web

ページは index.tsx のみ。
ページ内でListInput.tsx(リスト入力) と Slot.tsx(結果生成) を呼び出し、タブで出し分ける。

$ tree src 
src
├── components
│   ├── Footer.tsx
│   ├── LineShareButton.tsx
│   ├── ListInput.tsx
│   └── Slot.tsx
├── model
│   └── Food.ts
└── pages
    ├── _app.tsx
    └── index.tsx

結果生成

  • 入力されたリストをコピー
  • ランダムに並び替え
  • 欲しい数だけ前から切り取る
Slot.tsx
    const slot = () => {
        const copiedFoodList = foodList.concat();
        for (let i = copiedFoodList.length - 1; i > 0; i--) {
            const r = Math.floor(Math.random() * (i + 1));
            const tmp = copiedFoodList[i];
            copiedFoodList[i] = copiedFoodList[r];
            copiedFoodList[r] = tmp;
        }
        updateResult(copiedFoodList.slice(0, Number(count)));
    }

一点チェンジ

  • 入力されたリストをコピー
  • 選ばれているアイテムを除去
    • 候補がなければ終了
  • ランダムで一点選択
  • 上書き
Slot.tsx
    const slotOneItem = (index: number) => {
        const copiedFoodList: Food[] = foodList.concat();
        const remainingList: Food[] = copiedFoodList.filter((food) => !results.includes(food))
    
        if (remainingList.length == 0) {
            return;
        }

        const r = Math.floor(Math.random() * (remainingList.length));
        results[index] = remainingList[r];
        updateResult(results.slice(0, Number(count)));
    }

LINE Shareボタン

LineShareButton.tsx
const LineShareButton = (props: any) => {
    return (
        <Button sx={{ mx: 2, my: 2 }} variant="outlined" href={`https://line.me/R/share?text=${encodeURI(props.message)}`}>
            Share by LINE
        </Button>
    );
};

入力リスト保存

  • localStorage利用
  • 取得は初回呼び出しのみ
  • 書き込みは入力(foodListInputRaw)が変更が変更するたび
ListInput.tsx
    useEffect(() => {
        const foodListInputRaw = window.localStorage.getItem(STORAGE_KEY);
        if (foodListInputRaw !== null) {
            setFoodListInputRaw(foodListInputRaw);
        }
    }, []);

    useEffect(() => {
        const strList = foodListInputRaw.split('\n').filter(val => val);
        let index = 1;
        const newFoodList: Food[] = strList.map(name => ({ id: index++, name }));
        setFoodList(newFoodList);
        window.localStorage.setItem(STORAGE_KEY, foodListInputRaw);
    }, [foodListInputRaw, setFoodList]);

感想

localStorage、LINEシェアは初めて試したが簡単に使えてよかった。
技術の復習としてバックエンドも作りたかったが、要件的に不要になってしまい残念。
自分のほしいアプリケーションを作ると勉強したい技術が使えるとは限らないので、勉強目的なら勉強用のアプリケーションを作った方が無難そう。

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

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?