Stan Vuex przy odświeżaniu strony

113

Moja aplikacja korzysta z interfejsu API Firebase do uwierzytelniania użytkowników, zapisując stan logowania jako wartość logiczną w stanie Vuex.

Kiedy użytkownik się loguje, ustawiam status logowania i odpowiednio wyświetlam przycisk Zaloguj / Wyloguj.

Jednak po odświeżeniu strony stan aplikacji vue zostaje utracony i zresetowany do wartości domyślnych

Powoduje to problem, ponieważ nawet gdy użytkownik jest zalogowany, a strona jest odświeżana, status logowania jest ustawiany z powrotem na fałsz, a zamiast przycisku wylogowania wyświetlany jest przycisk logowania, mimo że użytkownik pozostaje zalogowany ....

Co mam zrobić, aby temu zapobiec

Czy mam używać plików cookie Czy jest dostępne inne lepsze rozwiązanie ...

    -
boomboxboy
źródło
2
Do tego celu używam dowolnego rodzaju pamięci lokalnej. To mogą być ciasteczka lub coś innego
Hammerbot
@El_Matella oprócz plików cookie, jakiej jeszcze metody używasz do przechowywania danych lokalnie
boomboxboy
1
Ogólnie używam pakietu npm magazynu lokalnego, który może wybrać najlepszą metodę przechowywania danych dla mnie: npmjs.com/package/local-storage "Interfejs API jest uproszczonym sposobem interakcji ze wszystkimi elementami localStorage. Pamiętaj, że gdy localStorage jest nieobsługiwany w bieżącej przeglądarce, powrót do magazynu w pamięci jest używany w sposób przezroczysty. "
Hammerbot
@El_Matella bardzo dziękuję ...
popatrzę

Odpowiedzi:

115

To znany przypadek użycia. Istnieją różne rozwiązania.

Na przykład można użyć vuex-persistedstate. To jest wtyczka vuexdo obsługi i przechowywania stanu między odświeżeniami strony.

Przykładowy kod:

import { Store } from 'vuex'
import createPersistedState from 'vuex-persistedstate'
import * as Cookies from 'js-cookie'

const store = new Store({
  // ...
  plugins: [
    createPersistedState({
      getState: (key) => Cookies.getJSON(key),
      setState: (key, state) => Cookies.set(key, state, { expires: 3, secure: true })
    })
  ]
})

To, co tutaj robimy, jest proste:

  1. musisz zainstalować js-cookie
  2. na getStatepróbujemy załadować zapisany stan zCookies
  3. na setStateratujemy nasz stanCookies

Dokumenty i instrukcje instalacji: https://www.npmjs.com/package/vuex-persistedstate

sobolevn
źródło
Dziękuję ... Właśnie
patrzyłem
9
Czy musisz zrobić coś konkretnego, aby ustawić / pobrać dane? Po ponownym załadowaniu moje dane są resetowane do wartości domyślnych. Wystarczy ustawić przez to. $ Store.state.user, wypróbowane obiekty i proste łańcuchy - bez powodzenia.
DogCoffee
6
Ponieważ pliki cookie są przesyłane między klientem a serwerem, prawdopodobnie zamiast tego spojrzałbym na pamięć lokalną ...
James Westgate,
jak zapisać stan aws-amplify? ponieważ jest zbyt duży, aby zmieścić się w plikach cookie, a lokalne przechowywanie nie będzie działać w prywatnym trybie safari
zaszczuty
@hounded Mam również ten sam problem, znalazłem jakieś rozwiązanie?
Adil
65

Tworząc stan VueX, zapisz go w pamięci sesji za pomocą wtyczki vuex-persistedstate . W ten sposób informacje zostaną utracone po zamknięciu przeglądarki. Unikaj używania plików cookie, ponieważ te wartości będą przesyłane między klientem a serwerem.

import Vue from 'vue'
import Vuex from 'vuex'
import createPersistedState from 'vuex-persistedstate'

Vue.use(Vuex);

export default new Vuex.Store({
    plugins: [createPersistedState({
        storage: window.sessionStorage,
    })],
    state: {
        //....
    }
});

Użyj, sessionStorage.clear();gdy użytkownik wyloguje się ręcznie.

James Westgate
źródło
13
Dziwię się, że rozwiązanie z ciasteczkami dostaje tyle gwiazdek. Myślę, że to rozwiązanie jest znacznie lepsze, ponieważ automatycznie usuwa cały stan po zamknięciu okna przeglądarki. Nie lubię wysyłać moich danych stanu jako plików cookie na serwer, a także nie chcę utrwalać poufnych danych po zamknięciu okna przeglądarki.
Mark Hagers
Masz również ograniczenie do 8k łącznie z nagłówkami, w tym plikami cookie.
James Westgate
2
@MarkHagers i jest natywnie obsługiwany od IE8! Nie ma potrzeby ładowania dodatkowego kodu.
Fabian von Ellerts,
1
Pojawił się błąd vuex-persistedstate.es.js?0e44:1 Uncaught (in promise) TypeError: Converting circular structure to JSON
Akin Hwan
1
@Akin - błąd sugeruje, że w swoim stanie masz odwołanie cykliczne, obiekt odwołuje się do innego obiektu, który ostatecznie odwołuje się z powrotem do pierwszego obiektu.
James Westgate
13

Stan Vuex jest przechowywany w pamięci. Wczytanie strony spowoduje wyczyszczenie obecnego stanu. Dlatego stan nie utrzymuje się przy przeładowaniu.

Ale vuex-persistedstatewtyczka rozwiązuje ten problem

npm install --save vuex-persistedstate

Teraz zaimportuj to do sklepu.

import Vue from 'vue'
import Vuex from 'vuex'
import account from './modules/account'
import createPersistedState from "vuex-persistedstate";

Vue.use(Vuex);

const store = new Vuex.Store({
  modules: {
    account,
  },
  plugins: [createPersistedState()]
});

Działało idealnie z pojedynczą linijką kodu: plugins: [createPersistedState()]

Rijo
źródło
10

Myślę, że użycie plików cookie / localStorage do zapisania stanu logowania może spowodować błąd w niektórych sytuacjach.
Firebase już rejestruje dla nas dane logowania w localStorage, w tym expirationTime i refreshToken.
Dlatego użyję haka utworzonego przez Vue i interfejsu API Firebase, aby sprawdzić stan logowania.
Jeśli token wygasł, interfejs API odświeży go za nas.
Dzięki temu możemy upewnić się, że stan logowania w naszej aplikacji jest taki sam, jak w Firebase.

new Vue({
    el: '#app',
    created() {
        firebase.auth().onAuthStateChanged((user) => {
            if (user) {
                log('User is logined');
                // update data or vuex state
            } else {
                log('User is not logged in.');
            }
        });
    },
});
Andrew - oahehc
źródło
najlepsze, oficjalne i rekomendowane podejście do tej sytuacji
alijunior
8

postaw na stan:

producer: JSON.parse(localStorage.getItem('producer') || "{}")

postaw na mutacje:

localStorage.setItem("producer",JSON.stringify(state.producer)) // OR
localStorage.removeItem("producers");

dla mnie działa dobrze!

Leonardo Filipe
źródło
2

Rozwiązałem to, resetując nagłówki za każdym razem, gdy ładuję ponownie, również pobieram dane użytkownika, nie wiem, co jest lepsze ...

new Vue({
    el: 'vue',
    render: h => h(VueBox),
    router,
    store,

    computed: {
        tokenJWT () {
            return this.$store.getters.tokenCheck
        },
    },


    created() {
        this.setAuth()

    },

    methods:
        Object.assign({}, mapActions(['setUser']), {

            setAuth(){
                if (this.tokenJWT) {
                    if (this.tokenJWT === 'expired') {
                        this.$store.dispatch('destroyAuth')
                        this.$store.dispatch('openModal')
                        this.$store.dispatch('setElModal', 'form-login')

                    } else {
                        window.axios.defaults.headers.common = {
                            'Accept': 'application/json',
                            'Authorization': 'Bearer ' + this.tokenJWT
                        }
                        axios.get( api.domain + api.authApi )
                            .then(res => {
                                if (res.status == 200) {
                                    this.setUser( res.data.user )
                                }
                            })
                            .catch( errors => {
                                console.log(errors)
                                this.destroyAuth()
                            })
                    }
                }
            }
        })

})
Alenn G'Kar
źródło