LoginSignup
1
0

More than 3 years have passed since last update.

コンポーネント間のデータのやりとりを簡単なTODOアプリでまとめる

Posted at

Vuexに頼りすぎてコンポーネント間のデータの受け渡し方が曖昧だったので、簡単なサンプルアプリでまとめる

また、Vueで開発をしていてコンポーネントを細かく分けない事で以下の問題がよく起こったのでその反省

コンポーネントを分けない問題
・汎用性の悪さ
例えばフォームとボタンを一緒のコンポーネントに作ると、ボタンだけ使い回したい時にフォームまでついてきて汎用性が悪い。

・同じような記述をしたコンポーネントファイルが増えDRYに反する

・1ファイルのコード量が増えて可読性が悪い

作成したコンポーネント

・ボタン
・入力フォーム
・ボタンと入力フォームをまとめたコンポーネント

ただ単にクリックイベントとボタン名を使いまわせるボタン

button.vue
<template>
  <button @click="onClick">{{name}}</button>
</template>
<script>
export default {
  props:{
    name:{
      type:String,
      default:"button"
    },
    onClick:{
      type:Function,
      required:true
    }
  },
}
</script>

入力フォーム。
propsの値はv-modelで直接変更するとエラーになる
computedでv-modelの変更を検知し
親コンポーネントへ入力された値(input)を送り、親側でpropsの値を更新する

Input.vue
<template>
<input type="text" v-model="input">
</template>
<script>
export default {
  props:{
    inputValue:String
  },
  computed:{
    // v-modelのinputの変更を検知
   input:{
     get(){
       return this.$props.inputValue
     },
    //  親コンポーネントにinputを送り出して親側でpropsの値を書き換える
     set(value){
        this.$emit("setValue",value)
     }
   }
  }
}
</script>

ボタンと入力フォームが存在するコンポーネント
入力フォームの値をボタンクリックで配列に格納し親コンポーネントへ渡す

Form.vue
<template>
  <div>
    <!-- $emitで渡ってきたイベントを実行 -->
    <!-- 子コンポーネントのpropsに$emitの引数で受け取った値をセット -->
    <Input
    @setValue="setValue"
    :inputValue = value />
    <!-- Buttonコンポーネントのイベント発火とボタン名を設定 -->
    <Button
    :onClick="postTodo"
    name="add"
     />
  </div>
</template>
<script>
import Button from "@/components/Button.vue"
import Input from "@/components/Input.vue"
export default {
  data(){
    return{
      value:null,
      todos:[]
    }
  },
  components:{
    Button,
    Input
  },
  methods:{
    postTodo(){
      this.todos.push(this.value)
      this.value=""
   //todoが追加された配列を親コンポーネントへ渡す
      this.$emit("setTodo",this.todos)
    },
    setValue(value){
      this.value=value
    }
  }
}
</script>

Form.vueから受け取った配列todosをv-forでレンダリング

App.vue
<template>
  <div id="app">
    <h1>Todo</h1>
    <Form 
    @setTodo="setTodo"
    />
    <hr>
    <template v-for="(todo,index) in todos">
      <li :key="index">{{todo}}</li>
    </template>
  </div>
</template>
<script>
import Form from "@/components/Form.vue"
export default {
  name: 'App',
  components: {
    Form
  },
  data(){
    return{
      todos:null
    }
  },
  methods:{
    setTodo(todos){
      this.todos=todos.reverse()
    },
  }
}
</script>

まとめ

・v-modelの値を渡したい時はcomputedで変更を検知して$emit経由で値を渡して親側からpropsを更新する
・$emitでどんどん親へ親へ渡していく。
・兄弟のデータを使う時は親のdataに保管したものを使う

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