Vuexでログイン認証の状態管理をしたい
vue.jsとfirebaseでwebサービス開発をしています。
ログイン認証機能を実装するにあたって状態管理にハマりまくりました。
大筋は、下記のチュートリアルを参考に行なっております。
Vue + Vue Router + Vuex + Laravelで写真共有アプリを作ろう (6) 認証機能とVuex
twitterでは何度紹介したかわかりませんがめちゃくちゃわかりやすいです。。本当に感謝
こちらのチュートリアルに沿って実装つつ、認証機能を、firebaseを使ったtwitterログインに置き換えて実装しています。
環境
MacOS HighSierra
vue.js 2.9.6
firebase 6.11.0
前提
- vue.js・Vuex・firebase・firestoreをインストール
- firebaseを使ってtwitterログイン認証を行う
- ユーザー情報をVuexのステートに格納する方法でログイン状態を管理する
やりたいこと
- ページをリロードしてもログイン状態を維持したい
- ページをリロードするとVueインスタンスが再生成されるため、ステートが初期値のnullに戻ってしまうことが問題でした。
処理の流れ
- ページリロード・ログイン後などVueインスタンスを生成する時に毎回ログイン状態を確認する
- ユーザーが存在していたらステート更新
問題点
- Vueインスタンス生成時に毎回ログイン状態を確認し、ユーザーがいたらステート更新、いなかったらnullとする
- 挙動自体はうまくいったのですが、下記のエラーが無限ループしていました。
[Vue warn]: Error in callback for watcher "function () { return this._data.$$state }":
"Error: [vuex] do not mutate vuex store state outside mutation handlers."
ソースコード
// Vueインスタンスを生成する関数
const createApp = () => {
// 認証状態を確認する
firebase.auth().onAuthStateChanged(user => {
if (user) {
// ユーザーが存在していたら、ストアにuser情報を渡す
store.dispatch('auth/currentUser', user)
} else {
// いなかったらnull
store.dispatch('auth/currentUser', null)
}
})
new Vue({
el: '#app',
'router': router,
'store': store,
components: { App },
template: '<App/>'
})
}
// 最後に関数実行
createApp()
const actions = {
currentUser (context, user) {
if (!user) {
context.commit('setUser', null)
} else {
// ステート更新
context.commit('setUser', user)
})
}
}
}
const mutations = {
setUser (state, user) {
// ユーザー情報を更新
state.user = user
}
}
原因と解決方法
「ミューテーションハンドラの外で変更するな」って怒られてる・・なんだこれってなってたんですが、違いました。
firebase.auth().onAuthStateChanged
の戻り値 user
をそのままセットしていたのが原因 でした。
user
に含まれている情報を改めて連想配列にセットし直すことで解決。
const actions = {
currentUser (context, user) {
if (!user) {
context.commit('setUser', null)
} else {
// userで得られた値でストアに入れたい情報をセットする
const currentUser = {
'displayName': user.displayName,
'photoURL': user.photoURL,
'uid': user.uid,
}
// ステート更新
context.commit('setUser', currentUser)
})
}
}
}
こちらを読んで思い至りました。
Vuex.store.stateの値をmutationsで変更しようとしたら、mutationsを使わずに値を変えるなと怒られた
// エラーメッセージ
[Vue warn]: Error in callback for watcher "function () { return this._data.$$state }":
"Error: [vuex] do not mutate vuex store state outside mutation handlers."
コールバック関数の戻り値でエラーを吐いているみたいなことが一文目に書いてありますね・・。
まとめ
Vueインスタンス生成時に認証状態を確認し、ステート更新処理を入れることで、ログイン状態を維持することができるようになりました。
firebaseを使うことによってOauth認証部分が楽チンに実装できるので嬉しいですね。
その分、firebaseの特性を知らないと思わぬところでハマるなあと思う日々であります。
同時に、今回初めてSPA書いているのですが、SPAの特性もよく理解する必要があるなぁと思うことしきりです。
勉強になりました。
おかしなところがあったら、コメント欄か、twitterでお教え頂けたら幸いですm(__)m