リロードしてもデータを保持するためには「localStorage」

###アプリを作った時悲しかったこと
プログラミングで初めて自分で作ったアプリ。Todoアプリなんかを駆け出しエンジニアの方々は作ったことだろう。
私もその一人です。
初めて自分で開発したアプリ、感動ものですよね。

完成したアプリの動作を確認します。
入力フォームにデータを入力して、保存ボタンを押して、データを表示させる。。。。
うまくいった！その時の嬉しさはなんとも言えないものがあります。



そして、ページをリロードっ！！！！
・・・・データが消えてる、、ページをリロードすると、、、データが消えてしまう。悲しい。

###localStorageメソッド
そんな駆け出しエンジニアの悩みを解決するメソッドがあります。
「localstorage」メソッドです。

追記：localStrage APIのセキュリティ上の問題点について興味深い記事があったので、一読ください。実際にアプリケーションを公開する場合は機密情報の保持等に気をつけて当APIを活用するのが好ましいと思われます。
（https://techracho.bpsinc.jp/hachi8833/2019_10_09/80851 ）

[MDN -Window.localStorage-](https://developer.mozilla.org/ja/docs/Web/API/Window/localStorage)

MDNの例文をconsole等で簡単に試して見ましょう。

ローカルのStorageオブジェクトにアクセスし、setItem()で値を追加します。

```javascript
localStorage.setItem('myCat', 'Tom');
```
getItem()で値を取得します

```javascript
var cat = localStorage.getItem("myCat");
console.log(cat)
//出力結果　> "Tom"
```

では、command + Rでページをリロードしてみましょう。
もう一度データを取得します。

```javascript
var cat = localStorage.getItem("myCat");
console.log(cat)
// 出力結果　> "Tom"
```


ページをリロードしても、データが取得できていることがわかります。


###少し実践
Reactでこのメソッドを使って、データを保持できるようにして見たいと思います。

```React:src/App.js
import React, { useEffect, useReducer } from 'react'

//省略

const APP_KEY = 'sampleApp'

const App = () => {
  const appState = localStorage.getItem(APP_KEY)
  const initialState = appState ? JSON.parse(appState) : {
    events: [],
    operationLogs: []
  }
  const [state, dispatch] = useReducer(reducer, initialState)

  useEffect(() => {
    localStorage.setItem(APP_KEY, JSON.stringify(state))
  }, [state])

  return (
    {/* ---------------------------

       ここに表示させたいフォーマットを書く

     ----------------------------------     */}
  
  )
}

export default App
```

上記のコードが何をしているのか解説します。
メソッドについて確認しておきましょう。
まずは、JSONを扱うメソッドについてです。

`JSON.parse()`
受け取った文字列をJSONに変換し、JavaScriptの値やオブジェクトを構築することができる

`JSON.stringify`
与えられたJavaScript の値を JSON 文字列に変換するメソッド

[MDN -JSON-](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/JSON)


以上のメソッドを理解したうえで、上記のコードを分解して見ていきましょう。

```javascript
const APP_KEY = 'sampleApp'

const App = () => {
  const appState = localStorage.getItem(APP_KEY)
  const initialState = appState ? JSON.parse(appState) : {
    events: []
  }

```

`localStorage.getItem()`を使って、ローカルStorageをリロードされた際に取得しています。値があるかどうかを三項演算子で判定していますが、もちろん、何もデータが格納されていない際には、initialStateには何も値が渡されないので、eventsオブジェクトには空配列が渡されます。

では、次です。

```javascript
const [state, dispatch] = useReducer(reducer, initialState)

  useEffect(() => {
    localStorage.setItem(APP_KEY, JSON.stringify(state))
  }, [state])
```

useReducerを用いて、値を保持しています。ここでは、フォーマットになんらかの値が入力され、値がreducerから返ってきたと仮定しましょう。

`useEffect`は第二引数に配列を渡すことができるので受け取ったstateをこのように格納して、保持することができます。

`localStorage.setItem()`を用いて、ローカルStorageにデータを追加します。データを表示するために`JSON.stringify()`メソッドを用いて、文字列に変化させていることにも注目してください。



それでは、また冒頭のコードに戻って見ましょう。

```javascript
const APP_KEY = 'sampleApp'

const App = () => {
  const appState = localStorage.getItem(APP_KEY)
  const initialState = appState ? JSON.parse(appState) : {
    events: []
  }
```


今度はローカルStrageに値があると仮定しているので、
`localStorage.getItem()`メソッドで値を取得できていることがわかります。
なので、initialStateの結果もtrueとなります。返り値はオブジェクトではなければならないので、`JSON.parse`を用いて、先ほど文字列に変換した値をまたオブジェクトに変換していることにも注目してください。


これで、リロードをしても値が保持できるようになると思います。

###まとめ

[MDN -Web Storage API を使用する-](https://developer.mozilla.org/ja/docs/Web/API/Web_Storage_API/Using_the_Web_Storage_API)
localStprageメソッドについて詳しく知りたい方は上記のリンクを参照してください。
今回はReactで作ったアプリを用いて解説してみましたが、ぜひ色々試して見てください。