Laravelやってみる#7―ナビゲーションバーの項目制御

Laravel 7.x

ぬにょす(挨拶)。

表題の通りですが、PHPフレームワークであるところのLaravelを使ってみようということで、やったこと・できたこと・できなかったこと等を自分の備忘録として残していきます。

#7の今回はログイン状態によりナビゲーションバーの項目を変更します。

v-if による制御

テンプレートでの表示のON/OFFは v-if / v-else ディレクティブを利用するだけです。

resources/js/components/NavbarComponent.vue
        <b-navbar-nav class="ml-auto">
          <!-- Authentication Links -->
          <template v-if="!username">
            <b-nav-item :to="{ name: 'login' }">Login</b-nav-item>
            <b-nav-item :to="{ name: 'register' }">Register</b-nav-item>
          </template>
          <b-nav-item-dropdown v-else right>
            <template v-slot:button-content>{{ username }}</template>
            <b-dropdown-item @click="logout">Logout</b-dropdown-item>
          </b-nav-item-dropdown>
        </b-navbar-nav>

username 変数に値がセットされているかどうかで、表示が切り替わります。

username はコンポーネントの mounted で APIを通じて取得しますが、その前に axios 周りに少し手を入れます。

async / await での利用

axios を使っていると then / catch のネストが深くなっていくことがあります。async / await を利用して if / else の見慣れた条件分岐にすることでコードの流れが直感的になります。

まずは axios のレスポンス処理を以下のように変更します。

resources/js/bootstrap.js
window.axios.interceptors.response.use(
    response => response,
    error => error.response
)

正常時でもエラー時でも response オブジェクトを返すようにします。呼び出し側では、ステータスコードを見て処理を分けます。以下のようなイメージです。

async function XXX() {
    const response = await axios.get('url')
    if (response.status === 200) {
        ...
    } else if (response.status === 401) {
        ...
    } else ... 

定数などの共通化

エラー処理で使うステータスコードなど、複数のVueコンポーネントで使う定数を共通化したいと思いました。

Vue.js の mixin を使って実装します。

まずは共通する内容を集めた common.js を作成します。

resources/js/mixins/common.js
export default {
    methods: {
        OK: function (response) {
            return response.status === 200
                || response.status === 204
        },
        UNAUTHORIZED: function (response) {
            return response.status === 401
        },
        UNPROCESSABLE_ENTITY: function (response) {
            return response.status === 422
        },
    },
}

このファイルを app.js でインポートし、Vue インスタンスにグローバルな mixin として登録します。

resources/js/app.js
import common from './mixins/common'
Vue.mixin(common)

各Vueコンポーネントでは、this を通じて mixin にアクセスします。処理を変更するついでに、/airlock/csrf-cookie へのおまじないリクエストは削除してしまいます。

resources/js/components/NavbarComponent.vue
  data: function() {
    return {
      username: ""
    };
  },
  mounted: async function() {
    this.username = "";
    const response = await axios.get("/api/user");
    if (this.OK(response)) {
      this.username = response.data.name;
    } else {
      console.log(response);
    }
  },
  methods: {
    logout: async function() {
      const response = await axios.post("/logout");
      if (this.OK(response)) {
        this.$router.push({ name: "welcome" });
      } else {
        console.log("Logout Error", response);
      }
    }
  }
resources/js/views/LoginView.vue
    login: async function() {
      this.errors = null;
      const response = await axios.post("/login", this.form);
      if (this.OK(response)) {
        this.$router.push({ name: "home" });
      } else if (this.UNPROCESSABLE_ENTITY(response)) {
        this.errors = response.data.errors;
      } else {
        console.log("Login Error", response);
      }
    }
resources/js/views/RegisterView.vue
    register: async function() {
      const response = await axios.post("/register", this.form);
      if (this.OK(response)) {
        this.$router.push({ name: "home" });
      } else if (this.UNPROCESSABLE_ENTITY(response)) {
        this.errors = response.data.errors;
      } else {
        console.log("Register Error", response);
      }
    }
resources/js/views/WelcomeView.vue
    onClick: async function() {
      this.message = "";
      const response = await axios.get("/api/user");
      if (this.OK(response)) {
        this.message = `Now ${response.data.email} is logged in.`;
      } else {
        this.message = `Oops! ${response.data.message}`;
      }
    }

実行結果

ログイン前とログイン後でナビゲーションバーの項目を変えることができました。

ここまでやってみて…

やっぱ気になるんですよね…。

レスポンスのステータスコードが4xxだと、ブラウザのデベロッパーツールにエラー表示されちゃうんですよね。自前で用意するAPIなら表面上は200を返して、dataの中に別のステータスコードを入れる等できますが、Laravelフレームワークのレスポンスはちょっとやそっとではカスタマイズできそうにないです。

ページ全体のリロードが発生しない点でSPAは魅力的ですが、機能やモデルが大きく異なるページまで全てひっくるめてSPAにする必要は無いのかな、と感じました。

コメント

タイトルとURLをコピーしました