初めてvueを触ってみた~propsの理解~
はじめに
こんにちは、SHIFT の開発部門に所属しているmurasawaです。今期より中途で入社、バックエンド関連の開発を担当しています。
現在、研修でデータベースやRestAPIについて基本的な事から学んでいます。学んだことをアウトプットし理解を深めていくとともに技術の共有としてお役に立てれば幸いです。
今回は私自身興味もあり、触ってみたいと思っていたこと、また業務で必要とされていたvue.js、vuetifyでのフロントエンド開発の際に困ったpropsについて調べてみました。
最初にpropsと言われても意味が分からず、何となく使っていたのですが、質問をしたりコードの流れを追うことで理解することができたので、初学者のとっかかりとなる記事になれば幸いです。
今回の説明で出てくるプログラムはVue CLIの<template>, <script>内に書くことを想定しています。
propsとは?
親コンポーネントから子コンポーネントに値を渡す際に使う変数のようなものです。
例えば、とあるサイトのユーザー情報画面をUserInfomation.vueとして実装。
UserInfomationのページの子要素として名前を入力するNameInput.vue、電話番号入力するPhoneInput.vueなどを実装し、UserInfomationのページでいろいろな情報を入力、編集できるようにしようとしています。
NameInput.vue、PhoneInput.vueというようにコンポーネントとして実装することで別ページで再度使用したり、入力コンポーネントとしてバリデーションや見た目などを作りこむことができます。
そこで、UserInfomation(親コンポーネント)とNameInput、PhoneInput(子コンポーネント)では値のやり取りが発生します。
・UserInfomationではデータベースから情報を取得したり、編集して更新する必要や取得した情報を初期値としてNameInput、PhoneInputに渡す必要がある。
・一方でNameInput、PhoneInputではユーザー情報を受け取り、入力内容をバリデーションしたり、整形して親コンポーネントに渡す必要がある。
その際に親から子にデータを渡すのに使うのがpropsになります。
実際のコード
子コンポーネントNameInput.vueでの記述
<template>
<v-text-field
:value="nameValue"
:rules="nameRules"
:clearable="clearable"
:readonly="readonly"
:counter="maxlen"
:isJapanese="isJapanese"
@change="nameChanged"
/>
</template>
<script>
export default {
model: {
prop: `nameValue`
},
props: {
nameValue: {
type: String,
required: false,
default: null
},
clearable: {
type: Boolean,
required: false,
default: true
},
readonly: {
type: Boolean,
required: false,
default: false
},
isJapanese: {
type: Boolean,
required: false,
default: false
}
},
data: () => ({
maxlen: 32
}),
computed: {
nameRules() {
return [
(v) => !!v || this.$t('errors.required', { key: this.$t('user_info.family_name') }),
(v) =>
(v && v.length <= this.maxlen) ||
this.$t('errors.maxlen', { key: this.$t('user_info.family_name'), maxlen: this.maxlen })
];
},
},
methods: {
nameChanged(value) {
this.$emit(`change`,value);
}
}
};
まず、v-text-fieldを使ってtemplateを作成します。
templateをもとにpropsで渡した値を使ってテキストボックスを作成できます。 以下の部分で定義しています。
<v-text-field
:value="nameValue" //valueを格納
:rules="nameRules" //validationの指定
:clearable="clearable" //clearボタン(×)表示
:readonly="readonly" //読み取り専用のフラグ
:counter="maxlen" //入力の際の最大文字数教示
:isJapanese="isJapanese" //言語を切り替えるときの処理指定
@change="nameChanged" //値が変わったときに実行する処理指定
/>
上記のようにv-text-fieldにもpropsがあり、:value="nameValue"と値 を渡すことができます。 ここでのnameValueのイメージです。
v-text-fieldは公式が作ってくれたコンポーネントという認識でよいと思います。(使用できるpropsは公式サイトを参照ください)
ここで指定したnameValueをもとにデフォルト値をテキストボックスに表示してくれます。
:value="nameValue"で指定したnameValue(ここではtaroになってますね)がNameInputに定義されているpropsです。
propsの定義は
model: {
prop: `nameValue`
},
props: {
nameValue: {
type: String,
required: false,
default: null
},
clearable: {
type: Boolean,
required: false,
default: true
},
readonly: {
type: Boolean,
required: false,
default: false
},
isJapanese: {
type: Boolean,
required: false,
default: false
}
}, ........
の部分で行っています。
少しややこしいですが、親コンポーネントからpropsであるnameValueに値が渡ってくる。そのnameValueをv-text-fieldのpropsであるvalueに渡している構図になります。
また
model: {
prop: `nameValue`
},
とすることでvalueのpropsをnameValueに置き換え、オブジェクトなどで複数の値を与えることもできるようになります。(特に特別な値を渡すのでなければmodelを設定する必要はありません。今回は説明のためあえて、設定しています。)
親コンポーネントUserInformation.vueでの記述
では次に親コンポーネント側のコードを見てみます。
<template>
<NameInput
:nameValue="nameValue"
:clearable="editable"
:readonly="!editable"
:isJapanese="isJapanese"
@change="onNameChange"
/>
</template>
<script>
import NameInput from './component/NameInput.vue';
export default {
name: 'userInformation',
data: () => ({
editable: false,
locale: 'japan',
nameValue: 'taro',
editable: true
}),
components: {
NameInput
},
computed: {
isJapanese() {
return this.locale === 'japan';
},
},
method: {
onNameCahnge(value) {
#子コンポーネントから帰ってきた値を処理する 。
#データベース更新や参照元の値を変更するなど
}
}
};
</script>
import NameInput from './component/NameInput.vue';
でコンポーネントを読み込み
components: {
NameInput
},
でコンポーネントとして定義しています。
<template>
<NameInput
:nameValue="nameValue"
:clearable="editable"
:readonly="!editable"
:isJapanese="isJapanese"
@change="onNameChange"
/>
</template>
dataやcomputedで定義した変数をNameInputのpropsに渡しています。
これで親コンポーネントから渡した値をもとにNameInputが作られます。
子コンポーネントから親コンポーネントへ値を渡す。
入力された値が変更されたときNameInput.vueのv-text-fieldで設定した
@change="nameChanged"
でmethodのnameChangedを実行しています。
@changeで値が変更されたときに指定した処理を実行することができます。
methods: {
nameChanged(value) {
this.$emit(`change`,value);
}
}
nameChangedが実行され this.$emit(`change`,value); により変更された値が親コンポーネントに渡されます。
親コンポーネント側では、
<template>
<NameInput
:nameValue="nameValue"
:clearable="editable"
:readonly="!editable"
:isJapanese="isJapanese"
@change="onNameCahnge"
/>
</template>
@changeで子コンポーネントの変更を受け取り、onNameCahngeを実行しています。 onNameCahngeで参照元のデータベースやオブジェクトなどを変更して、再度参照することで値が更新されます。
終わりに
vueを初めて触った際にpropsの部分ではまってしまいました。 vueがいろいろとよしなにやってくれるのもあり、何がどうなっているのか混乱してしまったのもあると思います。
今はpropsやv-modelとv-bind、createdやmountedの理解が進んで少しづつかけるようになったので、 その項目を記事化できればと思います。
お問合せはお気軽に
https://service.shiftinc.jp/contact/
SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/
SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/
SHIFTの導入事例
https://service.shiftinc.jp/case/
お役立ち資料はこちら
https://service.shiftinc.jp/resources/
SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/