クソ雑魚エンジニアのメモ帳

学んだことを書くところ

v-kansai Vue.js/Nuxt.js meetup#8 に参加しました!

こんばんは、さっきv-kansai#8に参加したところですがブログ書く枠なので ブログ書かされました書きました。よく考えたら久しぶりにはてぶろ更新した

vuekansai.connpass.com

vueとtypescriptと私

docs.google.com

vueとtypescriptの相性悪くない?→確かに複雑度が上がる

「型安全欲しくないですか?」ということで2パターンtypescriptの導入方法を紹介してました。

Vue.extendパターン

jsの状態からあまり変化なく自然に書けるパターン。全く知らなかった。

computed/data/watchは普通。

ただしpropsが一癖あるらしい

// component外部
type PropPbjType = {
  id: Number,
  name: String
}

// component内部
props: {
  val: String,
  obj: Object as PropType<PropObjType>
}

これは結構大変ですよね、複数人開発をしている場合とかに他人のcomponentのpropsの型を見るときにtypeで定義されていると型がわかりにくそう。それ以外は非常に良さげ :100:

vue-property-decoratorパターン

これは実務で使ったことあるパターンでした。vue要素が薄いのは本当にわかります。

「propsの!は必須。つけないとエラーが起こるらしい」→これはなったことがなかった。コンパイルオプションの設定次第(strictNullChecksとか?)なのかな?

vuexとtypescriptは一晩中話せる←この話がきになる

Google Nest HubでVue.jsを使った話、LINE Thingsでちょっとだけセキュアなシステム作った話

speakerdeck.com

LINE API EXPERTながおまるさんのお話。VUIめちゃつよな人が登壇してて本当に何でもできる方なんだなと思いました。

Google Nest HubでVue.jsを使った話

GoogleNestHubというデバイスに表示する画面を、vuejsを使ってInteractiveCanvasを操作できるという話(←あってるか怪しい)

どういうものを作ったのかはこの画像を見ると理解しやすそうでした

上の画像含めinteractiveCanvasはここら辺で詳しく見れそうです。

LINE Thingsでちょっとだけセキュアなシステム作った話

今年4月にLINEThingsが自動通信機能が搭載したらしく、 BLEに対応したIoTデバイスと端末が10m以内になったら、IoT→端末→(ネットワーク)→AWSlambda→AmazonConnectを通して送信できる。

IoTデバイス→端末(LINEThings)の接続はネット設定が不必要らしい。これはすごい。だいたいIoTデバイスの方がネット設定がないといけないIoTばかりなイメージ(知らんけど)なので驚きました

Function API You will use in future

speakerdeck.com

vue3が今年中に出る!?という話からvue3で採択予定のFunctionAPIについての話でした。

FunctionAPI

vue2でもプラグインを噛ませれば使えるとのこと

// yarn add vue-function-api

import {plugin} from "vue-function-api"

Vue.use(plugin)

簡単な例↓

<template>
  <div>
    <span>count is {{ count }}</span>
    <span>plusOne is {{ plusOne }}</span>
    <button @click="increment">count++</button>
  </div>
</template>

<script>
  import Vue from 'vue';
  import { value, computed, watch, onMounted } from 'vue-function-api'

  export default {
    setup() {
      // reactive state
      const count = value(0);
      // computed state
      const plusOne = computed(() => count.value + 1);
      // method
      const increment = () => {
        count.value++;
      };
      // watch
      watch(
        () => count.value * 2,
        val => {
          console.log(`count * 2 is ${val}`);
        }
      );
      // lifecycle
      onMounted(() => {
        console.log(`mounted`);
      });
      // expose bindings on render context
      return {
        count,
        plusOne,
        increment,
      };
    },
  };
</script>

https://github.com/vuejs/vue-function-api#single-file-component

setup()がなにやら色々やってそう。以下、setup()内で何をどう書くかについての説明

dataの作成

value関数を使う

const count = value(0)

dataへのアクセス

→{変数}.value

count.value

computedの定義

→関数で包む

const plusOne = computed(() => count.value+1)

methodsの定義

→関数で包む

const increment = () => {
  count.value++;
}

watchの定義

→関数で包む!?あれ?監視する値を関数で渡してる!?

watch(
  () => count.value*2,
  value => {
    console.log(`hogehoge`)
  }
)

FunctionAPI使わない書き方はこう

computed: {
  doubleValue() {
    return this.count * 2
  }
},
watch: {
  doubleValue(newValue) {
    console.log(`hogehoge`)
  }
}

FunctionAPIの場合は、内部的に count.value*2をcomputedに持ってるんですかねえ?奥が深い。。

総括として、(まるでReactやん)と(この書き方objectではなくfunctionの方が無駄が少なくない?)という感想が生まれた

後者に関しては、先ほどの例をこんな感じで書けないのか?という話

export default function(): Object {
      // reactive state
      const count = value(0);
      // computed state
      const plusOne = computed(() => count.value + 1);
      // method
      const increment = () => {
        count.value++;
      };
      // watch
      watch(
        () => count.value * 2,
        val => {
          console.log(`count * 2 is ${val}`);
        }
      );
      // lifecycle
      onMounted(() => {
        console.log(`mounted`);
      });
      // expose bindings on render context
      return {
        count,
        plusOne,
        increment,
      };
 };

RFCこちら

vueの好きさが伝わってきて、やっぱり学生って熱意すごいなと思いました。

NuxtとVuejsで読みづらいコード

(スライド未確認)

v-ifが多すぎる

<div v-if="status='active'">
  <button class="btn btn-active">アクティブ</button>
</div>
<div v-if="status='pending'">
  <button class="btn btn-pending">ペンディング</button>
</div>
<div v-if="status='complete'">
  <button class="btn btn-complete">完了</button>
</div>

みたいなコードができると、可読性が弱い・仕様変更に弱いという点で避けるべきという話。

→この場合は改善案としてstatusLabel()btnStyle()に分けるべきとのこと。

<buttn :class="btnStyle" class="btn">
  {{ statusLabeal }}
</button>

綺麗ですね :star:

v-ifが何個続いたら許せないか議論になりそう。僕は3つv-ifが出たら唸る自信がある

ちなみに僕だったらstatusLabelとbtnStyleをくっつける気がする(←論外)

props多すぎる問題

意味のある単位で渡すのが大事。

そもそも根本的な原因は?

役割・責務をよく考えずにcomponentを作っているせい

スーパーわかる。一定の親componentがある場合のみしか動作しない子componentとかはまさにそれ。

VuexFireSQLについて

docs.google.com

FireSQLとは

  • FirebaseをオマージュしたMySQL
  • リアルタイムにMySQLの変更を検知できる
  • マネージドMySQLでも可能

https://firebaseopensource.com/projects/jsayol/firesql/

やべーものがでてきたとおもった(小並感)

コネクションが枯渇しそうなのとフロントでSQLを発行できるのはセキュリティ的に大丈夫なのかについて気になったので本人に聞いて見たが、やっぱりそうらしい

Functional Component In Vuejs

slides.com

そういえばこの前全く自分もおんなじLTしてたなあと思った。振り返ると自分のLTはほんま完成度低かった

彼のはわかりやすくておしゃれですごかった。

Coreのバージョンが2.3.0以前の場合、 プロパティを受け入れる時は必須

全く知らなかった。

FPSは2倍ほど

やっぱりFunctionalComponentは早い。。

無限スクロールを導入する

(スライドがtwitterに上がってなかったので、ブログの方から拝借させていただきました🙇‍♂️)

webneko.dev

vue-infinite-loadingかと思ったらvue-infinite-loadingだった。

僕は泥臭そうな話が好きなので、PHPレンダリングしているvuejsのプロジェクトがどういうものなのか気になりました。

あまり無限スクロールの概念自体がわからない人が多いらしいですが、要はtwitterみたいなもんなのです。

vue-infinite-loadingの公式にデモがあるので見るとすぐにわかると思います。

https://peachscript.github.io/vue-infinite-loading/

無限スクロールを実装する時の他の選択肢として、 IntersectionObserverを使った実装もしたことがあるけどこっちは人気ないのかな、、

Mozillahttps://developer.mozilla.org/ja/docs/Web/API/Intersection_Observer_API

以下は僕がIntersectionObserver使った時のコード

<-- 何かしらのv-forするcomponent -->
<awesome-list v-for="item in items" :key="item.id" />

<-- 発火する基準となるDOM -->
<div refs="loading-spin">
    <div v-if="isLoading">読み込み中です</div>
    <div v-if="hasNoMoreData">全て表示しています</div>
</div>
{
    /**
     * Observerを設定
     */
    setIntersectionObserver() {
      const triggerElement = this.$refs['loading-spin'];
      if (!triggerElement) {
        return;
      }

      const observer = new IntersectionObserver(changes => {
        const clientHeight = document.documentElement.clientHeight;
        for (const change of changes) {
          const rect = change.target.getBoundingClientRect();
          // 画面内に入ったとき
          if (rect.top > 0 && rect.top <= clientHeight) {
            // まずObserver解除
            this.clearIntersectionObserver();
            // データを取得
            this.isLoading = true;
            
            // データの取得処理
            // promiseなりなんなり
            
            // 取得後にもう一度Observer設定
            this.$nextTick(() => {
              this.setIntersectionObserver();
            })
            this.isLoading = false;
          }
        }
      });

      // 監視開始
      observer.observe(triggerElement);
      this.observer = observer;
    },
    /**
     * observerを解除
     */
    clearIntersectionObserver() {
      if (!this.observer) {
        return;
      }

      this.observer.unobserve(this.$refs['loading-spin']);
      this.observer = null;
    },
}

総括

なんかやる気が出たので明後日LTすることにした。多分エラーのトラッキングの話

多少枠が空いているはずなのでみなさまぜひご参加ください

vuejs-osaka.connpass.com