グローバルナビゲーションへ

本文へ

フッターへ

お役立ち情報Blog



過去のコードをComposition APIを使って書き直してみる(後編)

前回の記事では、前編としてComposition APIについてまとめました。
Composition APIの基本的なsyntaxが分かったところで、実際に当ブログでご紹介した以下の記事のコードをComposition APIを用いて書き直してみたいと思います。

JavaScriptフレームワークの「Vue.js」を使ってToDoリストを実装してみよう(前編)
JavaScriptフレームワークの「Vue.js」を使ってToDoリストを実装してみよう(後編)


後編執筆までの間にVue3が公開されました!

※本記事は前回構築した「Vue2.x + @vue/composition-api」の環境で記載しています。

対象のコード

過去記事のコードの最終形

Vue-cliに載せ替える

過去記事のコードはhtml、js、cssの3ファイルで構成されていますので、まずはSFC(SingleFileComponents)化していきます。

前回記載の方法で設置したvue-cliにToDoコンポーネントを作成し、各ファイルを  <template>  <script>  <style> に移植して行きます。

現在の構成は以下のようになっています。

project-dir
  └ src
     ├ main.ts
     ├ App.Vue
     └ components
        └ ToDo.vue

ToDo.vueは以下のようになりました。
※長くなってしまうので、script部分のみになります。

<script lang="ts">
import Vue from "vue";

export default Vue.extend({
  data: () => {
    return {
      addText: "",
      list: [],
      uniqueKey: 0
    };
  },
  methods: {
    addToDo(): void {
      if (this.addText) {
        this.list.unshift({
          text: this.addText,
          id: this.uniqueKey + 1,
          flag: true
        });
      }
      this.addText = "";
      this.uniqueKey++;
    },
    deleteToDo(id: number): void {
      let deleteIndex = "";
      const check = confirm("本当に削除しますか?");
      if (check) {
        this.list.some(function(value, index) {
          if (value.id === id) {
            deleteIndex = index;
          }
        });
        this.list.splice(deleteIndex, 1);
      }
    },
    editToDo(id: number): void {
      const newText = window.prompt("以下内容で更新します。");
      if (!newText) {
        alert("入力欄が空欄です。");
      } else {
        this.edit(id, newText);
      }
    },
    edit(id: number, text: string): void {
      let editIndex = "";
      this.list.some(function(value, index) {
        if (value.id === id) {
          editIndex = index;
        }
      });
      this.list[editIndex].text = text;
    },
    changeToDo(id: number): void {
      let changeIndex = "";
      this.list.some(function(value, index) {
        if (value.id === id) {
          changeIndex = index;
        }
      });
      this.list[changeIndex].flag = this.change(changeIndex);
    },
    change(changeIndex: number): boolean {
      if (this.list[changeIndex].flag) {
        return false;
      } else {
        return true;
      }
    }
  }
});
</script>

Composition APIを用いて書き直し

次にComposition APIを用いて書き直します。
少しリファクタリングを行いましたが、ロジック自体は過去記事のものと同じになっています。

<script lang="ts">
import { defineComponent, reactive, ref } from "@vue/composition-api";

type List = {
  text: string;
  flag: boolean;
};

export default defineComponent({
  setup() {
    // data
    const addText = ref<string>("");
    const list = reactive<List[]>([]);

    // method
    const add = (): void => {
      if (addText.value) {
        list.splice(list.length + 1, 1, {
          text: addText.value,
          flag: true
        });
        addText.value = "";
      }
    };
    const remove = (key: number): void => {
      const check = confirm("本当に削除しますか?");
      if (check) {
        list.splice(key, 1);
      }
    };
    const edit = (key: number): void => {
      const newText = window.prompt("以下内容で更新します。");
      if (!newText) {
        alert("入力欄が空欄です。");
        return;
      }
      list[key].text = newText;
    };

    const change = (key: number): void => {
      list[key].flag = !list[key].flag;
    };

    return {
      addText,
      list,
      add,
      remove,
      edit,
      change
    };
  }
});
</script>

関数の切り出し

次に見通しを良くするために関数を切り出します。
 this が無いのですんなり切り出すことができました。

<script lang="ts">
import { defineComponent, reactive, ref } from "@vue/composition-api";

type List = {
  text: string;
  flag: boolean;
};

const Add = (list: List[]) => {
  const addText = ref<string>("");
  const add = (): void => {
    if (addText.value) {
      list.splice(list.length + 1, 1, {
        text: addText.value,
        flag: true
      });
      addText.value = "";
    }
  };
  return {
    addText,
    add
  };
};

const Remove = (list: List[]) => {
  const remove = (key: number): void => {
    const check = confirm("本当に削除しますか?");
    if (check) {
      list.splice(key, 1);
    }
  };
  return {
    remove
  };
};

const Edit = (list: List[]) => {
  const edit = (key: number): void => {
    const newText = window.prompt("以下内容で更新します。");
    if (!newText) {
      alert("入力欄が空欄です。");
      return;
    }
    list[key].text = newText;
  };
  return {
    edit
  };
};

const Change = (list: List[]) => {
  const change = (key: number): void => {
    list[key].flag = !list[key].flag;
  };
  return {
    change
  };
};

export default defineComponent({
  setup() {
    const list = reactive<List[]>([]);

    const { addText, add } = Add(list);
    const { remove } = Remove(list);
    const { edit } = Edit(list);
    const { change } = Change(list);

    return {
      addText,
      list,
      add,
      remove,
      edit,
      change
    };
  }
});
</script>

別ファイルへ切り出し

最後に各関数を別ファイルに切り出します。

現在の構成は以下のようになっています。

project-dir
  └ src
     ├ main.ts
     ├ App.Vue
     ├ components
     │  └ ToDo.vue
     ├ types
     │  └ List.ts
     └ functions
        ├ Add.ts
        ├ Remove.ts
        ├ Edit.ts
        └ Change.ts

各種functionは前項でdefineComponentの外に切り出したものを、そのままファイルに切り出しただけになります。

// 例:Add.ts
import { ref } from "@vue/composition-api";
import { List } from "@/types/List.ts";

export const Add = (list: List[]) => {
  const addText = ref<string>("");
  const add = (): void => {
    if (addText.value) {
      list.splice(list.length + 1, 1, {
        text: addText.value,
        flag: true
      });
      addText.value = "";
    }
  };
  return {
    addText,
    add
  };
};

最終的にToDo.vueは以下のようになりました。
別ファイルに切り出した関数をimportして使う形になっています。
とても見通しよくなったかと思います。

<script lang="ts">
import { defineComponent, reactive } from "@vue/composition-api";
// 各種functionをimport
import { List } from "@/types/List.ts";
import { Add } from "@/functions/Add.ts";
import { Remove } from "@/functions/Remove.ts";
import { Edit } from "@/functions/Edit.ts";
import { Change } from "@/functions/Change.ts";

export default defineComponent({
  setup() {
    const list = reactive<List[]>([]);

    // functionを定義
    const { addText, add } = Add(list);
    const { remove } = Remove(list);
    const { edit } = Edit(list);
    const { change } = Change(list);

    return {
      addText,
      list,
      add,
      remove,
      edit,
      change
    };
  }
});
</script>

まとめ

Vue3ではVue2.xと同様にOption APIを使ってコードを書くこともできますが、Composition APIを使って書くことでコードの切り出しや共通化がしやすくなります。

Vue3に対応していないmoduleでもOptions APIであればほぼそのまま使用可能ですが、Composition APIだと基本的には使えない(使えたとしてもComposition APIの利点を消してしまう)という問題もあります。

この記事を書いた人

ばね
ばねソリューション事業部 システムエンジニア
東京で2年半エンジニアとしての経験を積み、浜松にUターンの後、アーティスへ入社。
ソリューション事業部のWebエンジニアとして、システムの設計・開発・保守・運用からインフラまで幅広く従事している。
フルスタックエンジニア目指して現在も勉強の日々。車が好き。
この記事のカテゴリ

FOLLOW US

最新の情報をお届けします