ゲッタに対応したtoRef()とtoValue()
最後に紹介するのが、新機能リスト8のtoValue()です。この関数は、どちらかというと、コンポーザブルなどの関数内で利用するために新たに導入されたものであり、リアクティブ変数をリアクティブではないものへと変換するものです。
Refオブジェクトを生成するtoRef()
このtoValue()の導入に合わせて、その仕様が変更されたものとしてtoRef()があります。toRef()は、これまで、リアクティブなオブジェクトの個々のプロパティを独立したリアクティブな変数とする際に利用されてきた関数です。例えば、リスト8の(1)のリアクティブなオブジェクトであるmemberInfoのnameのみを、リアクティブな別の変数としたい場合に、リスト8の(2)のようなコードを記述して利用できます。
const memberInfo = reactive({ // (1) name: "田中太郎", state: "問題発生。" }); const memberInfoName = toRef(memberInfo, "name"); // (2)
この(2)のコードで、memberInfoNameはRefオブジェクト、つまりリアクティブな変数となり、しかも、その変数の値(memberInfoName.value)を変更すると、(1)のmemberInfo.nameも連動します。逆も然りです。
この仕組みは、PropsのひとつをRefに変更する際にもよく利用されます。例えば、外部のライブラリで用意されたコンポーザブル(関数)としてuseName()というのがあり、この引数がRefであるとします。そして、Propsとして受け取った値のひとつを、そのuseName()に渡す場合を考えます。この場合、リスト9のようなコードになります。
const props = defineProps<Props>(); const propsName = toRef(props, "name"); // (1) useName(propsName);
ここで、useName(props.name)というコードは記述できません。というのは、Propsの各値はRefではないからです。そこで登場するのが、リスト9の(1)のコードです。
ゲッタに対応したtoRef()
ただし、ここには問題があります。もし、Propsのnameがprops.nameのようにpropsオブジェクト直下の場合ならばよいのですが、もう1階層オブジェクトがネストされた状態でprops.memberInfo.nameのように、PropsのmemberInfoオブジェクトの中のnameプロパティである場合、リスト9(1)のコードは次のようになります。
const propsName = toRef(props.memberInfo, "name");
この場合、PropsのmemberInfoがundefinedかどうかを判断できなくなり、場合によってはエラーとなります。そこで、このような場合にcomputed()を利用してリスト10のようなコードを記述していました。
const propsName = computed( (): string | undefined => { return props.memberInfo?.name; } );
このcomputed()内部関数の処理は、単に値をリターンするだけのコードです。そして、このように単に値をリターンするだけの処理を、「ゲッタ(Getter)」と呼んでいます。
このゲッタに対してcomputed()を利用したコードは正しいのですが、computed()そのものがコンピュータリソースを必要とする処理であるためムダがあります。そこで今回新たに導入されたのが、toRef()でのゲッタ利用です。これは、リスト11のコードとなります。
const propsName = toRef( (): string | undefined => { return props.memberInfo?.name; } );
単にcomputed()の代わりにtoRef()を利用しただけであり、この仕組みにより、ゲッタをRefとして扱えるようになりました。
Refを値に戻すtoValue()
このゲッタに対するtoRef()のサポートと同時に導入されたのがtoValue()です。toValue()は、Refオブジェクト、すなわち、リアクティブ変数に対して適用させることで、リアクティブ変数ではない単なる値へと変更する関数です。例えば、リスト12のようなコードです。この場合、memberNameValueは単なる文字列の「田中太郎」になり、リアクティブ変数でなくなります。
const memberName = ref("田中太郎"); const memberNameValue = toValue(memberName);
ゲッタを直接引数とできるtoValue()
このようにリアクティブな変数をリアクティブでない変数へと変更したい際には、これまでは、unref()関数が利用されていました。ただし、unref()の場合は、リスト13のように、その引数にゲッタを渡すと動作がおかしいことになっていました。
const memberNameValue = unref( (): string | undefined => { return props.memberInfo?.name; } );
そこで、ゲッタを引数として、その値を適切に取り出せるように新たに導入されたのがtoValue()です。toValue()の引数を、リスト14のようにゲッタにしても、memberNameValueは、無事、単なる文字列かundefinedになるようになっています。
const memberNameValue = toValue( (): string | undefined => { return props.memberInfo?.name; } );
例えば、props.memberInfo.nameが「田中太郎」ならば、memberNameValueも「田中太郎」になります。
まとめ
Vue3.3の新機能を紹介する本稿の後編は、いかがでしたでしょうか。
前編の最初に紹介したように、このVue3.3で導入された新機能のおかげで、これまでバグを誘発しかねないコーディングを、そのコーディング段階から型チェックによって未然に防げるようになったものが多々あります。
簡単に言えば、より安心してコーディングできるようになるための新機能といえます。そのような内容が伝わったのでしたら嬉しい限りです。