Vue.js での「この単純なアプリケーション」にて入れ子を実現する
子から親を参照可能に
コンポーネント間の循環参照の記述の通り、
子側から親を配下のコンポーネントとするための記述を行うためには
beforeCreate
のタイミングで require
を実施するか、
components
への指定にて import
を行わせる
- Nuxt.js においては
require
ではうまくいかなかったので
両方うまくいったcomponents
でのimport
のほうがよさそうです
/components/TodoListItem.vue(子)
<script>
export default {
// Nuxt.js ではこちらのほうがうまくいった
components: {
TodoList: () => import("./TodoList.vue")
},
・・・
beforeCreate() {
// 親となっている TodoList を template にて使用可能とする
// - ただしこの記述は Nuxt.js ではうまくいかなかった
//this.$options.components.TodoList = require('./TodoList.vue')
}
・・・
};
</script>
data から props への変更による循環参照の回避
子側から呼び出し可能となったところで変更を行わず template に記載すると
循環参照によりエラーが発生するのでプロパティの種類を変更する
/components/TodoList.vue(親)
export default {
・・・
props: {
// あくまで親要素より受け取るという状態にすることで無限ループを回避
todos: {
type: Array,
// 「一番上」の TodoList 用にデフォルト値を指定する
default() {
return [
{
id: nextTodoId++,
text: 'Learn Vue'
},
{
id: nextTodoId++,
text: 'Learn about single-file components'
},
{
id: nextTodoId++,
text: 'Fall in love'
}
];
}
}
},
data () {
return {
newTodoText: '',
// TodoListItem より受け取れるよう独自のプロパティとしては持たせない
//todos: [
// {
// id: nextTodoId++,
// text: 'Learn Vue'
// },
// ・・・
//]
}
},
・・・
};
入れ子を実装
子であった TodoListItem にて TodoList を呼び出し
その子となる TodoList は呼び出しもとよりデータを受ける
/components/TodoListItem.vue(入れ子)
<template>
<li draggable="true">
{{ todo.text }}
<button @click="$emit('remove', todo.id)">
X
</button>
<!-- 入れ子を実装しつつ「子要素」への props down -->
<TodoList
:todos="todos"
/>
</li>
</template>
<script>
export default {
・・・
data() {
// もとは親であった TodoList のプロパティを TodoListItem 自身に持たせる
return {
todos: []
};
}
・・・
};
</script>
実例 (Warning 有)
・・・これだと削除時に「props」をいじるなと注意されてしまう
[Vue warn]:
Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders.
Instead, use a data or computed property based on the prop's value. Prop being mutated: "todos"
「prop の値を基に data を使いなさい」(おおまかに)
props down を行いつつ data も使用
props として配列を受け取り、そのまま使用していたことが問題を発生させていたので
props でいったん受けたものを data にて流用する形にする
/components/TodoList.vue
・・・
props: {
// ここでは todos を受け取らないように変更
prop_todos: {
type: Array,
default() {
return [
{
id: nextTodoId++,
text: 'Learn Vue'
},
・・・
];
}
}
},
data () {
return {
newTodoText: '',
// props の値を data として使用
todos: this.prop_todos
}
},
・・・
/components/TodoListItem.vue(todosからprop_todosへ)
<template>
<li draggable="true">
・・・
<!-- 渡す対象を prop_todos に変更 -->
<TodoList
:prop_todos="todos"
/>
・・・
</li>
</template>
実例 (props を data にして Warning 対応)
props への操作で Warning が発生して前述の事例を対応したもの
https://codesandbox.io/s/5vkv67yw4