ローカルストレージを活用

ローカルストレージを活用

投稿日: 2025年01月02日

学習振り返り
要約
  • ローカルストレージを使ってポケモンの名前を合言葉として保存するReactフックについて解説しています。
  • このフックは値の取得と設定を簡単にし、初回レンダリング時にローカルストレージから値を取得します。
  • パスワードが保存されていない場合は入力フォームを表示し、合言葉が正しければページにアクセスできる仕組みです。

はじめに

これはオリアプの第二弾の時のことなのですが、ポケモンの名前を合言葉にして、それをローカルストレージに保存するということをやりました。

同じデバイスではパスワードの入力が一度キリで済む感じです。

ちなみに私、一から書いてないです。

やってみようと決めてから実務でやったプロジェクトから使えそうでかつ、理解できるコードを探してくるという荒業を使っています。

フック見つけたのでいただきま~す!!って感じで自分のプロジェクトにコピペぺぺっとして終わりですw

恐らく自分でも書けると思いますが、なんせ私は常に時間に追われたせっかちなので、拝借できそうなものは拝借します。

私は素直な正直者です。

自分で書いた風に解説しつつ最後に出来上がったと見せかけて、拝借したコードを公開しますね。

フックになってるので大変ありがたかったです。

これ見た人そのまま使えちゃう。

ローカルストレージとは

Webページで取り扱うデータをブラウザに保存する仕組みのことです。

データには期限がないので、一度セットしたら基本的にずっとつかうことが出来ます。

ただし、削除やキャッシュクリアを行うとデータは消えてしまいますので、あくまで「原則ずっと使える」と考えてください。

詳しくはこちらをご覧ください。(私の逃げ道)


値をセットする

window.localStorage.setItem(key, value)

値を取得する

const value = window.localStorage.getItem(key);

取得・設定するフック

import { useState, useEffect } from "react";

type Response<T> = [T, (value: T) => void];

export const useLocalStorage = <T>(
  key: string,
  initialValue: T
): Response<T> => {
  const [value, setStoredValue] = useState<T>(initialValue);

  useEffect(() => {
    const getValue = (): T => {
      try {
        const item = localStorage.getItem(key);
        return item ? JSON.parse(item) : initialValue;
      } catch (e) {
        console.error(e);
        return initialValue;
      }
    };

    setStoredValue(getValue());
  }, [key, initialValue]);

  const setValue = (argValue: T): void => {
    try {
      setStoredValue(argValue);
      if (typeof window !== "undefined") {
        window.localStorage.setItem(key, JSON.stringify(argValue));
      }
    } catch (e) {
      console.error(e);
    }
  };
  return [value, setValue];
};

解説

解説と見せかけて自分の理解を確認しながら書いてます。ブログ書く意義。

まずは、このフックがレンダリングされた時点でローカルストレージの内容を取得します。

初回レンダリング時と依存配列が変更されたときに処理が走るuseEffectの部分です。

keyはフックの引数です。

第一引数のkeyに一致する値がセットされているか確認します。

あれば受け取れた値、なければ第二引数で受け取った値をステートにセットします。

その処理がこの部分で発火します。

setStoredValue(getValue())

次に、ローカルストレージに値を設定する処理です。

第一引数のkeyとvalueをセットします。

window.localStorage.setItem(key, JSON.stringify(argValue));

フックでは併せてステートにもvalueの値を設定しています。

ローカルストレージは文字列しか保存できないので、保存時には

JSON.stringify()

を使って文字列にして、オブジェクトや配列等を保存した時に備えて、取得した時には

JSON.parse()

しているわけです。

フックの返し値

 return [value, setValue];

配列を返します。valueには第一引数で受け取ったkeyでローカルストレージに保存されている値があればその値が入ります。なければ第二引数で受け取った値が入ります。

setValueはローカルストレージに値をセットする処理とフック内のステートの値を更新する処理が含まれている関数です。

この関数を実行するとvalueの値が更新されると同時にローカルストレージに保存ができる、使い方はステートの更新関数と同じ使い方です。

型決まってます。

type Response<T> = [T, (value: T) => void];

基本的にTypeScriptは型を推論してくれるので、返し値の型はわざわざ定義する必要がないことが多いのですが、今回は明示的に定義しておかないとuseStateの仕様で上手くいかないので定義してあります(あるようです)。

定義しない場合、

(value: T) => void

T|(value: T) => void

と推論されてしまって。返しているのはTの型のvalueを引数に取る関数でありTではないので、明示的に指定しています。

TypeScriptの推論結果として意図しない型が生成されるということです。

パスワードの保存に使う際のロジック

このフックを利用する側の話です。

初期化

const [password, setPassword] = useLocalStorage<string>("password", "");

今回は合言葉なのでpasswordとしています。

keyは"password"valueは空の文字列です。

型引数は今回保存したいのただの文字列なので、stringです。

ここで、保存されている値があれば(=初回ログインでなければ) passwordに値が入るはず。

なので、一つフックを(usePassword)挟むのですが

"use client";
import { RoomIndex } from "./_components/RoomIndex";
import { usePassword } from "./_hooks/usePassword";
import { InputPassword } from "./_components/InputPassword";
export default function Page() {
  const { password, error, checkPassword, inputValue, setInputValue } =
    usePassword();

  if (!password)
    return (
      <InputPassword
        checkPassword={checkPassword}
        error={error}
        inputValue={inputValue}
        setInputValue={setInputValue}
      />
    );

  return <RoomIndex />;
}

こんな感じで、passwordなければ入力フォーム、あればログイン後の処理に進んでます。

合言葉さえ知っていればだれでも見れるページという仕様だからです。通常のログインの場合はログイン処理をする必要があります!

パスワードの保存がなかった場合は、入力フォームを表示し入力してもらってからそのパスワードがあっているかという確認を行う処理をしています。

全部やってると長くなるのでこの辺にしておきます。

おわりに

ローカルストレージ、めちゃくちゃ使えますよね。

ブラウザのキャッシュクリアしたりすると多分なかったことになるので再度入力求められるのかなと思います。

万能フックが拝借出来てありがたかったです。

でもこのフックがあってもそれを使いこなせるかも大事なので、ただのセコイ奴ではないと信じたいです。。。

実務課題までクリアした人あるあるだと思います。(よね?こうすけさん、参考というか同じ処理するならそのコード頂いたりするよね??※道連れ)

新年早々こんな感じで申し訳ないですが、絶対誰かのお役に立てると信じていますw

本年もよろしくお願いいたします!!

シェア!

Threads
user
吉本茜
山口在住/二児の母/育休中
Loading...
記事一覧に戻る
Threads
0