なぽろぐ

気ままに感じたことを記事にまとめます。

vue-promisedとcomposition-apiがよさそう

vue-promisedとcomposition-apiを併用してみる

適当にコードだけ貼り付けていた記事がGoogleの検索上位にいたので,これでは情報が少なすぎる・・・・と思い書き直しました.

f:id:Naporitan:20191226023408p:plain:w300

公式の次に出てくる記事がコード貼り付けて動かしてるだけじゃダメでしょ・・・・・・

vue-promisedとは

github.com

PromiseをUI側で処理してあげるのが旨味となります.

created, methodsでasync/awaitすれば解決じゃない?って思うかもしれませんが,Pendingの時はローディングを出して,resolveされたらコンテンツを表示,rejectされたらエラー表示するという時を考えてみます.

そうするとPromiseの状態をUIに伝えるためのFlag変数が必要となり意味の薄い変数がPromiseの数分だけ増えて行きますよね.そこでUI側でPromiseの状態を判別して適切なUIを返してくれるVue-Promiseが嬉しいというわけです.

Flagを持たせて書いてみる

<template>
    <div>
        <div v-if="isPending">
            <p>loading</p>
        </div>
        <div v-else-if="isResolve">
            <p>{{content}}</p>
        </div>
        <div v-else>
            <p>fetch error</p>
        </div>
    </div>
</template>

<script>
import axios from "axios";

export default {
    data() {
        return {
            isPending: false,
            error: "",
            content: {},
        }
    },
    computed: {
        isResolve() {
           return !this.isPending && !error && !!content;
        }
    },
    async created() {
        try {
            const res = await axios.get("http://example.com");
            this.content = res.data;
        } catch (e) {
              this.error = "error";
              console.error(e);
        } finally {
            this.isPending = false;
        }
    }
}
</script>

Vue-Promisedで書いてみる

template層で使うpromise変数にPromiseを渡せばいいです.他はtemplateそうがやってくれるのでロジック側ではPromiseの状態をハンドリングすることなく,resolveされた後のデータ,rejectされた後のデータをどう使うか,だけに絞って書くことができるので非常に簡潔に,そしてわかりやすくかけると思います.

PromiseはUIに任せる.Angulerだと普通みたいですが,僕はVue-Promisedに感激しました.

<template>
  <Promised id="app" :promise="promise">
    <template v-slot:pending>
      <p>loading....</p>
    </template>
    <template v-slot="data">
      <p>{{data}}</p>
    </template>
    <template v-slot:rejected="error">
        {{error}}
    </template>
  </Promised>
</template>

<script>
import { Promised } from "vue-promised";
import axios from "axios";

export default {
  components: { Promised },
  data: {
        return {
            promise: axios.get("http://example.com")
        }
  }
};
</script>

-----------------------------ここまで書き直した------------------------------------

vue-composition-api

vue-composition-api-rfc.netlify.com

<template>
  <Promised id="app" :promise="user">
    <template v-slot:pending>
      <p>loading....</p>
    </template>
    <template v-slot="user">
      <p>{{`${user.firstName}${user.lastName}`}}</p>
    </template>
  </Promised>
</template>

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

interface User {
  firstName: string;
  lastName: string;
}
export default createComponent({
  components: { Promised },
  setup() {
    const delayPromise = (time: number) =>
      new Promise(resolve => {
        setTimeout(() => {
          resolve();
        }, time);
      });
    const fetchUser = async (): Promise<User> => {
      await delayPromise(1000);
      return {
        firstName: "naporitan",
        lastName: "napo"
      };
    };
    const user = ref(fetchUser());
    return { user };
  }
});
</script>

Image from Gyazo

promiseをそのまま変数に突っ込んでview側でpromiseを切り分けてくれるのでcreated, mountedで頑張らなくていいのとloadingフラグとか持たなくてよくなるので楽だなぁて感じです。

vue-promisedをjsxで書こうとしたら

JSX 要素型 'Promised' にはコンストラクトも呼び出しシグネチャも含まれていません。

って言われるんだけど、どうしたらいいんだろう。

だからできるはずなんだけどなぁ

Vueの情報収拾をほとんどここでやっています。ラジオ感覚で聞けて助かってる。 uit-inside.linecorp.com