tomatoaiu の Tech Blog

プログラミングやツールについてのまとめブログ

Vue.jsでObjectを子コンポーネントにpropsで渡すいくつかの方法

いくつかの方法

だいたい4つぐらいがありそう。

環境

  • 【Editor】: VS Code
  • 【Terminal】: Iterm2
  • 【Shell】: zsh
  • 【PackageManager】: Yarn
  • 【Vue Style】: Vue Class Style Component
  • 【Vue Script Language Block】: TypeScript

Objectをそのまま渡す

親コンポーネント

<template>
  <div id="app">
    <ChildComponent :porps-for-child="propsForChild"/>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ChildComponent from './components/ChildComponent.vue';

@Component({
  components: {
    ChildComponent,
  },
})
export default class App extends Vue {
  propsForChild = {
    from: 'Parent',
    to: 'Child',
  }
}
</script>

子コンポーネント

<template>
  <p>{{ propsForChild }}</p>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

type PropsForChild = {
  from: string,
  to: string
}

@Component
export default class ChildComponent extends Vue {
  @Prop() private propsForChild!: PropsForChild;
}
</script>

Object内でプロパティを指定し渡す

親コンポーネント

<template>
  <div id="app">
    <ChildComponent :porps-for-child="{
      from: 'Parent',
      to: 'Child'
    }"/>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ChildComponent from './components/ChildComponent.vue';

@Component({
  components: {
    ChildComponent,
  },
})
export default class App extends Vue {
  propsForChild = {
    from: '',
    to: '',
  }
}
</script>

子コンポーネント

<template>
  <p>{{ propsForChild }}</p>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

type PropsForChild = {
  from: string,
  to: string
}

@Component
export default class ChildComponent extends Vue {
  @Prop() private propsForChild!: PropsForChild;
}
</script>

プロパティのみを渡す

親コンポーネント

<template>
  <div id="app">
    <ChildComponent
      :from="propsForChild.from"
      :to="propsForChild.to"
    />
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ChildComponent from './components/ChildComponent.vue';

@Component({
  components: {
    ChildComponent,
  },
})
export default class App extends Vue {
  propsForChild = {
    from: 'Parent',
    to: 'Child',
  }
}
</script>

子コンポーネント

<template>
  <p>{{ from }} {{ to }}</p>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class ChildComponent extends Vue {
  @Prop() private from!: string;

  @Prop() private to!: string;
}
</script>

Objectを省略記法を使いそのまま渡す

親コンポーネント

<template>
  <div id="app">
    <ChildComponent v-bind="propsForChild"/>
  </div>
</template>

<script lang="ts">
import { Component, Vue } from 'vue-property-decorator';
import ChildComponent from './components/ChildComponent.vue';

@Component({
  components: {
    ChildComponent,
  },
})
export default class App extends Vue {
  propsForChild = {
    from: 'Parent',
    to: 'Child',
  }
}
</script>

子コンポーネント

<template>
  <p>{{ from }} {{ to }}</p>
</template>

<script lang="ts">
import { Component, Prop, Vue } from 'vue-property-decorator';

@Component
export default class ChildComponent extends Vue {
  @Prop() private from!: string;

  @Prop() private to!: string;
}
</script>

どれがいいのか

Objectをそのまま渡す

  • メリット
    • 親のtemplate内の見通しがよくなる
    • 値のバケツリレーする量が多くなると見やすい
  • デメリット
    • どんなプロパティを渡しているかtemplate内からでは判断できない
    • 中継をするようなコンポーネントならなおさらどんなプロパティを渡しているか分からない
    • TypeScriptでtypeを付けないと辛い

Object内でプロパティを指定し渡す

  • メリット
    • どんなpropsでどんなプロパティを渡すのか明確
  • デメリット
    • そのままObjectを渡すよりも冗長な感じ
    • TypeScriptでtypeを付けないと辛い

プロパティのみを渡す

  • メリット
    • 子コンポーネントで具体的にpropsの指定を書くことができる
    • どんな値を受け渡すのか分かりやすい
    • 子コンポーネント側で標準のvueを使い具体的な型について書ける
  • デメリット
    • 値のバケツリレーする量が多くなると見づらい
    • templateの風通しが悪い

Objectを省略記法を使いそのまま渡す

  • メリット
    • Objectをそのまま渡すよりも短く書くことができるかもしれない
    • 子コンポーネントで具体的にpropsの指定を書くことができる
    • 子コンポーネント側で標準のvueを使い具体的な型について書ける
  • デメリット
    • どんな値を受け渡すのか分かりにくい
    • 省略記法への知識がいる

どれを使うべきか

一概にこれのみを使えとは言えない。どれがいいのか設計に応じて決めるべきな感じ。
個人的には、Object内でプロパティを指定し渡す方法を使うようにした方がいい気がする。この書き方で、TypeScriptで型を付けて、vueのrequired等のオプションを付けて、computedでObjectを綺麗に分けるのがbetterな感じがする。

備考導入編

今回のobjectをpropsに渡すにあたり作成した流れを記す。

vue cliがどうなってた確認。

~/development 28s
❯ yarn global list
yarn global v1.9.2
info "@vue/cli@3.0.0-rc.4" has binaries:
   - vue

うん。古いね。
アップデート。

~/development
❯ yarn global add @vue/cli
yarn global v1.15.2
〜〜〜中略〜〜〜
success Installed "@vue/cli@3.7.0" with binaries:
      - vue
✨  Done in 27.11s.

一応しっかし、バージョンアップできてるか確認。

~/development 7s
❯ vue --version
3.7.0

じゃあプロジェクト作成するぞ!

~/development
❯ vue create vue-props-test


Vue CLI v3.7.0
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript for auto-detected polyfills? Yes
? Pick a linter / formatter config: Airbnb
? Pick additional lint features: Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No
〜〜〜中略〜〜〜
success Saved lockfile.
✨  Done in 22.84s.
⚓  Running completion hooks...

📄  Generating README.md...

🎉  Successfully created project vue-props-test.
👉  Get started with the following commands:

 $ cd vue-props-test
 $ yarn serve

できたので、コマンドを実行して、vscodeを開く。

cd vue-props-test
code .

srcフォルダ

どんな感じにsrcフォルダができているか見る。

~/development/vue-props-test master
❯ tree ./src
./src
├── App.vue
├── assets
│   └── logo.png
├── components
│   └── HelloWorld.vue
├── main.ts
├── shims-tsx.d.ts
└── shims-vue.d.ts

2 directories, 6 files

↑を↓にする。

~/development/vue-props-test master*
❯ tree ./src
./src
├── App.vue
├── components
│   └── ChildComponent.vue
├── main.ts
├── shims-tsx.d.ts
└── shims-vue.d.ts

成果物

https://github.com/tomatoaiu/vue-props-sample

参考文献

基礎から学ぶ Vue.js

基礎から学ぶ Vue.js

  • 作者:MIO
  • 発売日: 2018/05/29
  • メディア: Kindle版