Vue.js でのツリー構造など循環参照の具体的コピペ

# Vue.js での[「この単純なアプリケーション」](https://codesandbox.io/s/o29j95wx9)にて入れ子を実現する

## 子から親を参照可能に

[コンポーネント間の循環参照](https://jp.vuejs.org/v2/guide/components-edge-cases.html#コンポーネント間の循環参照)の記述の通り、
子側から親を配下のコンポーネントとするための記述を行うためには
`beforeCreate` のタイミングで `require` を実施するか、
`components` への指定にて `import` を行わせる

* Nuxt.js においては `require` ではうまくいかなかったので  
  両方うまくいった `components` での `import` のほうがよさそうです

```vue:/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 に記載すると
循環参照によりエラーが発生するのでプロパティの種類を変更する

```js:/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 は呼び出しもとよりデータを受ける

```html:/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 有)

https://codesandbox.io/s/3r7kopo0pp

・・・これだと削除時に「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 にて流用する形にする

```js:/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
    }
  },
  ・・・
```

```html:/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