LoginSignup
0
1

More than 1 year has passed since last update.

Vue.js+Vuexの行儀の悪い脱法コード3つ

Posted at

これは「「はじめに」の Advent Calendar 2021」13日目の記事です。

※コンポーネントの種類、用語は Atomic design をベースにしています。

脱法1. Atom/MoleculesからActionを呼び出す

  • 理由
    • Atom/MoleculesとVuexのstateが強い結合をもつ。
    • 挙動が一緒で読み出すstateが違うパーツが大量生産される
FooPage.vue
<template>
  <ButtonFoo />
  <ButtonBar />
  <ButtonBaz />
</template>
<script>
import ButtonFoo from '@/components/ButtonFoo.vue'
import ButtonBar from '@/components/ButtonBar.vue'
import ButtonBaz from '@/components/ButtonBaz.vue'

  components: {
    ButtonFoo, ButtonBar, ButtonBaz
  }
</script>
ButtonFoo.vue
<template>
  <button @click="onClick">{{ name }}</button>
</template>
<script>

export default {
  computed: {
    name() {
      return this.$store.getters.foo.name;
    }
  },
  methods: {
    ..mapActions('foo', ['getName'])
    onClick() {
      this.getName()
    }
  }
}
</script>
store/modules/foo.js
export default {
  namespaced: true,
  mutations: {
    FOO_NAME: (state, name) => {
      state.name = name
    }
  },
  actions: {
    getName({ commit }) {
      asyncApi().then(response => {
        commit('FOO_NAME', response.data)
      }
    }
  }
}
  • 合法化するには
    • Atom/Moleculesへ値を渡すときはprops
    • Atom/Moleculesでの操作やイベントは$emit
    • Actionの呼び出しはPagesに集約させる
FooPage.vue
<template>
  <ButtonFoo :name="foo" @foo-click="getFoo()" />
  <ButtonFoo :name="bar" @foo-click="getBar()" />
  <ButtonFoo :name="baz" @foo-click="getBaz()" />
</template>
<script>
import ButtonFoo from '@/components/ButtonFoo.vue'

export default {
  computed: {
    foo(): { return this.$store.getters.foo.name; },
    bar(): { return this.$store.getters.bar.name; },
    baz(): { return this.$store.getters.baz.name; },
  },
  methods: {
    ..mapActions('foo', ['getName'])
    getFoo() {
      foo.getName()
    }
    // (略)
  }
}
</script>
Button.vue
<template>
  <button @click="onClick">{{ name }}</button>
</template>
<script>

export default {
  props: {
    name: {
      type: String,
      default: "init"
    }
  },
  methods: {
    onClick() {
      this.$emit()
    }
  }
}
</script>

脱法2: actionの戻り値をHookして自コンポーネント内のdataに保存する

  • 理由
    • Vuexの単方向データフローコンセプト違反。
    • SSOT(Single Source Of Truthe)違反。
    • storeとコンポーネント内のdataの整合性の保証がない

FooPage.vue
<template>
  <ButtonFoo :name="name" @foo-click="getFoo()" />
</template>
<script>
import ButtonFoo from '@/components/ButtonFoo.vue'

export default {
  data() {
    return {
      name: ""
    }
  }
  computed: {
    foo() { return this.$store.getters.foo.name; },
  },
  methods: {
    ..mapActions('foo', ['getName'])
    getFoo().then {
      foo.getName().then((data) => {
        this.name = data
      })
    }
  }
}
</script>
store/modules/foo.js
import { getName } from '@/api/foo'

export default {
  namespaced: true,
  mutations: {
    FOO_NAME: (state, name) => {
      state.name = name
    }
  },
  actions: {
    return new Promise((resolve, reject) => {
      getName({ commit }): {
        asyncApi().then(response => {
          commit('FOO_NAME', response.data)
          resolve(response.data)
        }.catch((e) => {
          reject(e)
        })
      }
    }
  }
}
  • 合法化するには
    • actionsは、mutations にわたすデータを返り値にしない。
    • 同じ内容を保存するのは1箇所にする

※コードは1と同様なので割愛

脱法3: Atom/Moleculesがapiをダイレクトコール

  • 理由
    • アプリケーションデータを一元管理できない(どこで保存されているかわからなくなる)
    • APIとコンポーネントの結合が強くなると変更に弱い
    • APIのスキーマ変更の追従が困難になる

スキーマをそのままstateに利用しているコードも行儀は良くない。
パット見、独立したデータフローサイクルが構築されているので、問題ないように見えるコトがあるのが厄介。

Button.vue
<template>
  <button @click="onClick">{{ name }}</button>
</template>
<script>
import { getName } from '@/api/foo'

export default {
  data() {
    return {
      name: ""
    }
  },
  methods: {
    onClick() {
      getName().then((response) => {
        this.name = response.data
      })
    }
  }
}
</script>
  • 合法化するには
    • api呼び出しはactions経由に集約する。
      • APIのスキーマ変更に対しては、Vue.jsアプリケーション内のデータモデルとAPIのレスポンスモデルを別に定義しておくこと。OpenAPIを利用した自動生成を使うことで管理コストは削減観光。
    • (例外)アプリケーションのメインデータではないもの、ライブラリとして切り離せるもの。
      • 郵便番号から住所文字列をサジェストする再利用可能なOrganizmsなど
0
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
0
1