5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Vue 3のCompositional APIでRefをComponentに渡す方法

Posted at

目的

Compositional APIのrefを別Componentに渡すこと。

背景

React・VueでFormを作る時に、ごちゃごちゃ防止として以下のHTMLを一つのComponentにまとめたい。

<div class="some-class">
 <title>Some Title</title>
 <input type="text" />
</div>

ただ、Componentにrefを渡さなければいけず、ここでややこしくなります。

React.jsだと、forwardRefという関数を使うと、簡単にクリアできますが、Vue 3はそうでもないのです。

ここで、JavaScriptの魔法を使って、解決法を解説します。

InputのComponentを作る

このように作ります。

BaseInput.vue

<template>
  <div>
    <label :for="name">{{ title }}</label>
    <input :type="type" ref="ref" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    type: { type: String, required: true },
    name: { type: String, required: true },
    title: { type: String, required: true },
    inputRef: { required: true },
  },
  setup() {},
});
</script>

FormのComponentも作ろう

NewPost.vue

<template>
  <form @submit="handleSubmit">
    <BaseInput title="Title" name="title" :inputRef="titleRef" type="text" />
    <button type="submit">Submit</button>
  </form>
</template>

<script lang="ts">
import { defineComponent, ref } from "vue";
import BaseInput from "./UI/BaseInput.vue";

export default defineComponent({
  components: {
    BaseInput,
  },
  setup() {
    const titleRef = ref<HTMLInputElement>();

    const handleSubmit = (event: Event) => {
      event.preventDefault();
      if (titleRef.value) {
        console.log(titleRef.value.value);
      }
    };

    return {
      handleSubmit,
    };
  },
});
</script>

JS魔法:渡したいrefを関数に包む

JavaScriptの信者じゃなければ納得はいかんと思います。

NewPost.vueのsetupがreturnするObjectに、titleRefを返す関数を入れるのです。

    return {
      titleRef: () => titleRef,
      handleSubmit,
    };

ここでBaseInput.vueに戻って、この関数を実行した上でTemplateに渡します。

setupにpropsを入れます。

BaseInput.vue

<template>
  <div>
    <label :for="name">{{ title }}</label>
    <input :type="type" ref="ref" />
  </div>
</template>

<script lang="ts">
import { defineComponent } from "vue";

export default defineComponent({
  props: {
    type: { type: String, required: true },
    name: { type: String, required: true },
    title: { type: String, required: true },
    inputRef: { type: Function, required: true },
  },
  setup(props) {
    return {
      ref: props.inputRef(),
    } 
  },
});
</script>

まとめ

これでCompositional APIのrefを渡してスッキリしたFormを作れます!

本当は、ReactみたいにちゃんとしたforwardRef機能をつけてほしいところですね。

5
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?