60434


vuetify＋vue-cliで講義の欠席回数カウントするTodoリストを作っています。

# 環境

windows10(64)  
"vue": "^2.6.10",  
"vuetify": "^2.1.0",  
"vue-cli":"3.11.0",  
"node":"v11.13.0"  
プログラミング歴 ４か月ほど

# 発生している問題

jsのlocalStorageという機能を使ってデータの永続化を試みているのですが、下記のような問題が発生しています。  
授業名を２つ以上登録した状態でメモ（フィールド）に文字を入力し、その状態でページロードすると後から入力した内容に全て書き変わってしまう。  
このやりたいことを _「問題➀」_ とします。  
百聞は一見に如かずなので、下記で「問題➀」を画像でも説明します。  
➀ 経済学（授業名）に（ええええ）と入力します。  
[![画像の説明をここに入力](https://i.stack.imgur.com/u4kuI.png)](https://i.stack.imgur.com/u4kuI.png)  
➁ 次に再読み込みします。  
[![画像の説明をここに入力](https://i.stack.imgur.com/NHgjO.png)](https://i.stack.imgur.com/NHgjO.png)  
➂ すると、スポーツ科学にも経済学で入力した「ええええ」が反映されてしまっています。これを反映しないようにしたいです。  
[![画像の説明をここに入力](https://i.stack.imgur.com/Czk9S.png)](https://i.stack.imgur.com/Czk9S.png)

# ソースコード

現在、vuex、コンポーネントの受け渡しは勉強中なので使用できていません。またメモ（フィールド）の部分のみコンポーネントで分けていることに疑問を持たれると思いますが、理由は後で説明します。  
_Count.vue_

[code]

    <template>
      <v-app>
        <v-content>
          <v-container>
            <v-row>
              <v-col cols="6">
                <v-text-field v-model="name" label="授業名" @keyup.enter="addTodo" required></v-text-field>
              </v-col>
            </v-row>
            <div v-for="(todo,index) in todos" :key="todo.name">
              <v-card card_id max-width="344" class="mx-auto">
                <v-card-title>{{todo.name}}</v-card-title>
                <v-card-text>
                  <Field />
                </v-card-text>
                <v-card-actions>
                  <v-btn @click="increment(todo)" color="primary">さぼり回数</v-btn>
                  <span>{{ todo.count }}</span>
                  <v-btn @click="decrement(todo)" color="error">間違い（－）</v-btn>
                  <v-btn @click="deleteItem(index)">削除</v-btn>
                </v-card-actions>
              </v-card>
            </div>
          </v-container>
        </v-content>
      </v-app>
    </template>
    
    <script>
    import Field from "./Field";
    
    export default {
      data() {
        return {
          count: 0,
          name: "",
          todos: []
        };
      },
      components: {
        Field
      },
      mounted() {
        this.todos = JSON.parse(localStorage.getItem("todos")) || [];
      },
      methods: {
        addTodo() {
          if (this.name != "") {
            this.todos.push({
              name: this.name,
              count: 0
            });
          }
          this.templateJson();
          this.name = "";
        },
        increment(todo) {
          todo.count++;
          this.templateJson();
        },
        decrement(todo) {
          if (todo.count > 0) {
            todo.count--;
          }
          this.templateJson();
        },
        deleteItem(index) {
          this.todos.splice(index, 1);
          let setJson = JSON.stringify(this.todos);
          localStorage.removeItem("todos");
          localStorage.setItem("todos", setJson);
        },
        templateJson() {
          let setJson = JSON.stringify(this.todos);
          localStorage.setItem("todos", setJson);
        }
      }
    };
    </script>
    
[/code]

_Field.vue_

[code]

    <template>
      <v-text-field label="メモ" v-model="memo"></v-text-field>
    </template>
    
    <script>
    export default {
      data() {
        return {
          memo: ""
        };
      },
      mounted() {
        if (localStorage.memo) this.memo = localStorage.memo;
      },
      watch: {
        memo(newMemo) {
          localStorage.memo = newMemo;
        }
      }
    };
    </script>
    
[/code]

# なぜField.vueのみコンポーネントで分けたのか

実はこの * 問題➀* に遭遇するまでに、フィールドを入力すると全てのフィールドに入力した文字が同時に反映されてしまうという問題が発生していました。  
この問題を「問題➁」とします。ここで <https://teratail.com/questions/222231>、「問題➁」に関して質問しています。  
その「問題➁」の解決策としてやけくそですが、メモの部分のみコンポーネント(Field.vue)で分けてみました。  
するとフィールドに入力した文字が別のフィールドに同時に反映されてしまうという _問題➁_ は解決できました。  
しかし、その後「問題➀」であるページロードすると後から入力した内容に全て書き変わってしまうという新しい問題が発生しました。

# エラー文

コンソールのエラーはありませんでした。  
[![画像の説明をここに入力](https://i.stack.imgur.com/D5orh.png)](https://i.stack.imgur.com/D5orh.png)

次にストレージ内の状況です。  
[![画像の説明をここに入力](https://i.stack.imgur.com/Id2ay.png)](https://i.stack.imgur.com/Id2ay.png)

# 全コード

<https://github.com/masal9pse/courageTodo/tree/develop2>

# 参考にしたサイト

１つ目： <https://jp.vuejs.org/v2/cookbook/client-side-storage.html>  
２つ目： <https://jj-tech-blog.com/%E3%80%90vue-
js%E3%80%91localstorage%E3%81%AB%E3%83%87%E3%83%BC%E3%82%BF%E3%82%92%E4%BF%9D%E5%AD%98%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95>

色々と調査をしてみたのですが、原因が全く分からないため同じ現象に遭遇したことがある方、もしくは何か原因に関して、お心辺りのある方がいらっしゃいましたら解決方法に関してアドバイス頂けないでしょうか？


CC BY-SA 4.0
2019-11-11T18:25:05.437
60422
2019-11-12T06:11:07.800
2019-11-12T06:11:07.800
36424
36424
question
javascript vue.js
vue-cli、再読み込みすることでのデータの永続化が全てに反映されてしまう問題について


`<v-text-field label="メモ" v-model="memo"></v-text-field>`
の部分はアプリケーション全体で一つのメモを変数 `meme` に保持して、複数個所からその一つのメモを編集するという意味になります。  
また localStorage はアプリケーション全体で共通ですので、今の Field の実装は各 Field コンポーネントごとにある別々の memo
プロパティを変更の度に localStorage 経由で同期する実装になっていて、こちらも一つのメモを全ての Field から編集する動作になってます。

そうではなくてTODO毎にメモを持ちたいということでしたら `<Field />` の部分を  
`<v-text-field label="メモ" v-model="todo.memo"></v-text-field>`  
のようにします。

ここでは Field コンポーネントは使ってませんが、データの保持＆読み込み＆保存を Count コンポーネントで行い、その値を Field
にバインドしても同じことはできます。  
しかし、今 `<v-card>` になっている範囲を Todo コンポーネントとして切り出して、 todo
の1要素にバインドするのが素直な設計になりそうです。


CC BY-SA 4.0
2019-11-12T03:27:25.903
60434
2019-11-12T03:27:25.903
241
60422
answer