Tatsuya Asami
8 min readMar 9, 2019

--

アドバイスをもらって修正した。とりあえず「親のコンポーネントのtemplateをすっきりさせたい。」という目的は達成できた。

まだこの辺ちゃんと理解できてない。

親から子にデータを渡す。

→Propsを通じて子で受け取ったデータはそのまま編集できない(この段階では親のデータのイメージ)ので、そのまま子のデータに入れる。

→子で編集。

→子のデータをwatchし、$emitで親のデータに返す。(子で編集した内容が常に親のデータにも反映されている)

という流れ。

これを踏まえて今回は

  • 1つの親に対して3つの子がある
  • 3つの子はどれも同じデータを必要としている

という条件。

  • 複数の子で扱うデータは親が持つ(data.todos)
  • 親のデータを子で編集したい場合は、最初に書いた通り。子の中で一時的にデータを持って親に返しているが、データを子から親に送るというよりは、親のデータを子で編集しているイメージ。
  • $emitを使えば親のmethodsを利用するのは簡単なので、親が持つデータを必要とするmethodsは親で宣言し、子ではemitを使って呼び出せばいい。Propsで渡す内容が少なくなり、楽に書ける(InputeArea.vue)
  • 一方で、親から子に渡して、子で完結するフィルタリング機能など(TaskList.vueのcomputed)は子に渡した。基本的にはコンポーネントの中で行われることは同じコンポーネントにあった方がわかりやすいですよね?(TaskList.vue)
    TaskList.vueはtodosの表示を取り扱うコンポーネントだが、ここで編集したデータは他のコンポーネントに影響を与えない。
// Hello.vue<template>
<div>
{{ msg }}
<InputArea
:new-todo="newTodo"
@input="input"
@addTodo="addTodo"
@removeTodo="removeTodo"
/>
<ToggleArea @changeShowTodo="changeShowTodo" />
<TaskList :todos="todos" :show-todo="showTodo" />
</div>
</template>
<script>
import InputArea from "@/components/InputArea.vue";
import TaskList from "@/components/TaskList.vue";
import ToggleArea from "@/components/ToggleArea.vue";
export default {
name: "Hello",
components: {
InputArea,
TaskList,
ToggleArea
},
data: function() {
return {
msg: "Welcome to my Todo",
todos: [
{ id: 1, text: "vue-router", done: false },
{ id: 2, text: "vuex", done: false },
{ id: 3, text: "vue-loader", done: false },
{ id: 4, text: "awsome-vue", done: false },
{ id: 5, text: "vue-router", done: true }
],
newTodo: "",
showTodo: "all"
};
},
methods: {
input: function(child) {
this.newTodo = child;
},

addTodo: function() {
let text = this.newTodo && this.newTodo.trim();
if (!text) {
return;
}
const id = this.todos.slice(-1)[0].id + 1;
this.todos.push({
id: id,
text: text,
done: false
});
this.newTodo = "";
},
removeTodo: function() {
for (let i = this.todos.length - 1; i >= 0; i--) {
if (this.todos[i].done) this.todos.splice(i, 1);
}
},
changeShowTodo: function(e) {
this.showTodo = e;
}
}
};

親のdata.newTodoを編集するコンポーネント

// InputArea.vue<template>
<div class="input-area">
<button @click="addTaskFromChild">ADD TASK</button>
<button @click="$emit('removeTodo')">DELETE FINISHED TASKS</button>
<p>
input:
<input v-model="childInput" type="text" />
</p>
<p>task:{{ childInput }}</p>
</div>
</template>
<script>
export default {
name: "InputArea",
props: {
newTodo: {
type: String,
default: function() {
return "";
}
}
},
data: function() {
return {
childInput: this.newTodo
};
},
watch: {
// newTodo: function(oldVal) {
// this.childInput = oldVal;
// console.log(oldVal);
// },
childInput: function(newValue) {
this.$emit("input", newValue);
}

},
methods: {
addTaskFromChild: function() {
this.$emit("addTodo");
this.childInput = "";
}
}
}
;
</script>

親データを子がPropsで受け取るのと、子が$emitで親データに送るのを両方watchすると無限ループになる。

ToggleArea.vueではデータは受け取らず、emitで親にある関数を実行した。

// ToggleArea.vue<template>
<div>
<div class="toggle-area">
<button @click="$emit('changeShowTodo', 'all')">All</button>
<button
@click="$emit('changeShowTodo', 'inProgress')">
In progress
</button>
<button
@click="$emit('changeShowTodo', 'done')">Done</button>
</div>
</div>
</template>
<script>
export default {
name: "ToggleArea"
};
</script>

TaskList.vueは元々あったように、親からデータを受け取り、子コンポーネント内で編集をしている。

<追記>

vuexの動画見てたら出てきたやり方。このやり方でOKならこれの方がシンプル。computedのgetとsetを使う。

親のnewTodoをpropsで子に送る

→子ではcomputedのgetでnewTodoを表示

→編集したデータは親のinputに返す

→親のinputが親にあるnewTodoを更新する。

という流れ。

<template>
<div class="input-area">
<button @click="$emit('addTodo')">ADD TASK</button>
<button @click="$emit('removeTodo')">DELETE FINISHED TASKS</button>
<p>
input:
<input v-model="inputValue" type="text" />
</p>
<p>task:{{ inputValue }}</p>
</div>
</template>
<script>
export default {
name: "InputArea",
props: {
newTodo: {
type: String,
default: function() {
return "";
}
}
},
computed: {
inputValue: {
get() {
return this.newTodo;
},
set(value) {
this.$emit("input", value);
}
}
}
};
</script>

--

--

Tatsuya Asami
Tatsuya Asami

Written by Tatsuya Asami

Front end engineer. React, TypeScript, Three.js

No responses yet