見出し画像

12 LocalStorageでデータを永続化

今回の学習ポイントは下記となります。

LocalStorageを使って、入力したデータを永続化させる方法、保存したデータを読み出す方法について見ていきます。

LocalStorageの確認
mounted

LocalStorage
watch
deep watcher

ウォッチャとは

多くの場合では算出プロパティの方が適切ではありますが、カスタムウォッチャが必要な時もあるでしょう。データの変更に対して反応する、より汎用的な watch オプションを Vue が提供しているのはそのためです。データが変わるのに応じて非同期やコストの高い処理を実行したいときに最も便利です。

例:

<div id="watch-example">
 <p>
   Ask a yes/no question:
   <input v-model="question">
 </p>
 <p>{{ answer }}</p>
</div>
<!-- ajax ライブラリの豊富なエコシステムや、汎用的なユーティリティ	-->
<!-- メソッドがたくさんあるので、Vue のコアはそれらを再発明せずに	-->
<!-- 小さく保たれています。この結果として、慣れ親しんでいるものだけを	-->
<!-- 使えるような自由さを Vue は持ち合わせています。			-->
<script src="https://cdn.jsdelivr.net/npm/axios@0.12.0/dist/axios.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/lodash@4.13.1/lodash.min.js"></script>
<script>
var watchExampleVM = new Vue({
 el: '#watch-example',
 data: {
   question: '',
   answer: 'I cannot give you an answer until you ask a question!'
 },
 watch: {
   // この関数は question が変わるごとに実行されます。
   question: function (newQuestion, oldQuestion) {
     this.answer = 'Waiting for you to stop typing...'
     this.debouncedGetAnswer()
   }
 },
 created: function () {
   // _.debounce は特にコストの高い処理の実行を制御するための
   // lodash の関数です。この場合は、どのくらい頻繁に yesno.wtf/api
   // へのアクセスすべきかを制限するために、ユーザーの入力が完全に
   // 終わるのを待ってから ajax リクエストを実行しています。
   // _.debounce (とその親戚である _.throttle )  についての詳細は
   // https://lodash.com/docs#debounce を見てください。
   this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
 },
 methods: {
   getAnswer: function () {
     if (this.question.indexOf('?') === -1) {
       this.answer = 'Questions usually contain a question mark. ;-)'
       return
     }
     this.answer = 'Thinking...'
     var vm = this
     axios.get('https://yesno.wtf/api')
       .then(function (response) {
         vm.answer = _.capitalize(response.data.answer)
       })
       .catch(function (error) {
         vm.answer = 'Error! Could not reach the API. ' + error
       })
   }
 }
})
</script>

結果:

この場合では、watch オプションを利用することで、非同期処理( API のアクセス)の実行や、処理をどのくらいの頻度で実行するかを制御したり、最終的な answer が取得できるまでは中間の状態にしておく、といったことが可能になっています。これらはいずれも算出プロパティでは実現できません。


いろいろな機能を作ってきましたが、今はブラウザをリロードしてしまうとまた元に戻ってしまうので、 LocalStorage を使ってデータを永続化してみましょう。


データの保存ですが、 todolistに何らかの変更が加えられたときに行えばいいです。


したがって、この辺りのメソッドのこのあたりの処理の前後に仕込んでもいいのですが、 watch という仕組みを使えば、指定したデータの変更を監視してくれます。 では watch としてあげて、 todos に変更があったときには次の処理をしなさいよ、と書いてあげます。

    watch: {
     todos: function() {
             localStorage.setItem('todos', JSON.stringify(this.todos));
             alert('Data saved!');
      }
     },

ここで LocalStorage にデータを保存したいので、 setItem() としつつ、 todos というキーで todos の値を JSON 形式にしてあげて保存しています。


上手くこの処理が走っているかをどうか確認したいので、 alert() をつけてあげます。  


ただし、チェックしたときには Data saved! と出ていないのがわかるかと思います。 

 
これはなぜかというと、単に todos をこのように watch しただけだと、 todos の配列自体に変更があったときにはこちらの処理は実行してくれるのですが、配列の中身の要素、今回だと title だとか isDone の変更までは監視してくれないという仕組みになっているためです。


これを直すには、データの中身も含めて監視する必要があって、 deep watcher という仕組みを使わないといけません。


ちょっと書き方に癖があるのですが、 todos の中身を監視するときに、実際に行う処理は handler で書いてあげて、 deep オプションを true にしてあげれば OK です。

    watch: {

     todos: {
       handler: function() {
         localStorage.setItem('todos', JSON.stringify(this.todos));
         // alert('Data saved!');
       },
       deep: true
     }
   },

追加したときにもアラートが出ていますし、チェックしたときにもアラートが出ているので OK かと思います。


今、データの保存はできているのですが、データを追加してブラウザをリロードしても、データが読み出せていないので最初の状態に戻っています。


そこで、データを読み出したいのですが、その前にちゃんと保存されているか確認してみます。


保存されたデータを見るには Developer Tools を使ってあげればいいです。


macOS だと option + command + I で開くので、その中の Application パネルを見てあげます。
LocalStorage なのですが、今は file にアクセスしているので、 LocalStorage の中の file を見て、 todos のキーでちゃんとこのような値が保存されているのがわかるかと思います。 

では、このデータをどのタイミングで呼び出すかですが、 Vue.js のインスタンスにはライフサイクルが定義されていて、今回はアプリがページにマウントされるタイミングでデータを読み込んであげます。        

マウントされるタイミングは mounted としてあげて、そのときの処理を関数の中に書いていけば OK です。 

  mounted: function() {
     this.todos = JSON.parse(localStorage.getItem('todos')) || [];
   },


this.todos に対して JSON を parse しつつ、 localStorage から todos のキーでデータを getItem() してあげれば OK です。


JSON の parse が上手くいかなかった場合は、空の配列にしたいので || 演算子を使ってあげて、このように書いてあげてもokです。
あとは todos の初期化もいらないので、ただの空配列にしておきます。


そしてwebでいろいろ追加して、ブラウザをリロードしてもそのままなので。

以上todolistの紹介は全部完了しました。

ここから先は

2,594字
この記事のみ ¥ 100

この記事が気に入ったらサポートをしてみませんか?