Estado de Vuex en la actualización de la página

106

Mi aplicación usa la API de Firebase para la autenticación de usuarios, y guarda el estado de inicio de sesión como un valor booleano en un estado de Vuex.

Cuando el usuario inicia sesión, configuro el estado de inicio de sesión y visualizo condicionalmente el botón Iniciar sesión / Cerrar sesión en consecuencia.

Pero cuando se actualiza la página, el estado de la aplicación vue se pierde y se restablece al valor predeterminado

Esto causa un problema, ya que incluso cuando el usuario está conectado y la página se actualiza, el estado de inicio de sesión se establece de nuevo en falso y se muestra el botón de inicio de sesión en lugar del botón de cierre de sesión, aunque el usuario permanece conectado ...

¿Qué debo hacer para prevenir este comportamiento?

¿Debo usar cookies o hay otra solución mejor disponible?

    -
boomboxboy
fuente
2
Utilizo cualquier tipo de almacenamiento local para manejar eso. Pueden ser galletas o algo más
Hammerbot
@El_Matella aparte de cookies qué método más se puede utiliza para almacenar datos localmente
boomboxboy
1
En general, utilizo un paquete npm de almacenamiento local que puede elegir el mejor método para almacenar datos: npmjs.com/package/local-storage "La API es una forma simplificada de interactuar con todo lo relacionado con localStorage. Tenga en cuenta que cuando localStorage es no admitido en el navegador actual, se utiliza de forma transparente una alternativa a un almacén en memoria ".
Hammerbot
@El_Matella muchas gracias ... voy a echar un vistazo
boomboxboy

Respuestas:

110

Este es un caso de uso conocido. Existen diferentes soluciones.

Por ejemplo, se puede usar vuex-persistedstate. Este es un complemento para vuexmanejar y almacenar el estado entre actualizaciones de página.

Código de muestra:

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 })
    })
  ]
})

Lo que hacemos aquí es simple:

  1. necesitas instalar js-cookie
  2. en getStateintentamos cargar el estado guardado deCookies
  3. en setStatesalvamos nuestro estado paraCookies

Documentos e instrucciones de instalación: https://www.npmjs.com/package/vuex-persistedstate

sobolevn
fuente
Gracias ... Estaba mirando la página de github del complemento ... Gracias una vez más
boomboxboy
8
¿Necesita hacer algo específico para configurar / obtener los datos? Al recargar mis datos se restablecen a los valores predeterminados. Simplemente estableciendo a través de este. $ Store.state.user, probé objetos y cadenas simples, sin suerte.
DogCoffee
6
Debido a que las cookies se transmiten entre el cliente y el servidor, probablemente buscaría el almacenamiento local en su lugar ...
James Westgate
¿Cómo guardo el estado de aws-amplify? ya que es demasiado grande para caber en las cookies y el almacenamiento local no funcionará en el modo privado de safari
acosado el
@hounded También estoy enfrentando el mismo problema, ¿encontró alguna solución para esto?
Adil
54

Al crear su estado de VueX, guárdelo en el almacenamiento de la sesión con el complemento vuex-persistedstate . De esta forma, la información se perderá cuando se cierre el navegador. Evite el uso de cookies ya que estos valores viajarán entre el cliente y el servidor.

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: {
        //....
    }
});

Úselo sessionStorage.clear();cuando el usuario cierre la sesión manualmente.

James Westgate
fuente
13
Me sorprende que la solución de cookies obtenga tantas estrellas. Creo que esta solución es mucho mejor, ya que borra automáticamente todos los estados cuando se cierra la ventana del navegador. No me gusta enviar mis datos de estado como cookies al servidor, y tampoco quiero conservar los datos confidenciales cuando se cierra la ventana del navegador.
Mark Hagers
También está limitado a 8k en total con sus encabezados que incluyen cookies.
James Westgate
2
@MarkHagers y es compatible de forma nativa desde IE8. No es necesario cargar código adicional.
Fabian von Ellerts
1
Recibía un error vuex-persistedstate.es.js?0e44:1 Uncaught (in promise) TypeError: Converting circular structure to JSON
Akin Hwan
1
@Akin: el error sugiere que tiene una referencia circular en su estado, un objeto hace referencia a otro objeto que finalmente hace referencia al primer objeto.
James Westgate
11

El estado de Vuex se guarda en la memoria. La carga de la página purgará este estado actual. Es por eso que el estado no persiste en la recarga.

Pero el vuex-persistedstatecomplemento resuelve este problema

npm install --save vuex-persistedstate

Ahora importe esto a la tienda.

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()]
});

Funcionó perfectamente con una sola línea de código: plugins: [createPersistedState()]

Rijo
fuente
10

Creo que usar cookies / localStorage para guardar el estado de inicio de sesión podría causar algún error en alguna situación.
Firebase ya registra la información de inicio de sesión en localStorage para nosotros, incluidos expirationTime y refreshToken.
Por lo tanto, usaré el gancho creado por Vue y la API de Firebase para verificar el estado de inicio de sesión.
Si el token expiró, la API actualizará el token por nosotros.
Entonces, podemos asegurarnos de que la visualización del estado de inicio de sesión en nuestra aplicación sea igual a 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.');
            }
        });
    },
});
Andrés - oahehc
fuente
el mejor enfoque, oficial y recomendado contra esta situación
alijunior
8

poner en estado:

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

poner mutaciones:

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

funciona bien para mi!

Leonardo Filipe
fuente
1

Resolví esto restableciendo mis encabezados cada vez que recargo, también obtengo datos de usuario, no sé qué es mejor ...

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
fuente