Как исправить проблему синхронизации id пользователя в Pinia при обновлении localStorage после аутентификации?
Суть логики:
В данном шаблоне комментария, если пользователь аутентифицирован, то его комментарии подкрасится в такой цвет: bg-indigo-100, если нет, то будет bg-white. Логика работает по принципу: comment.authorId === productCommentsStore.loginId, id пользователя из бд === id пользователя из бд записанный в локальное хранилище.
id пользователя из бд я получаю с помощью запроса handleAddComment в store комментариев, а id пользователя из локального хранилища я получаю в другом store при аутентификации в данной функции:
handleSubmit
В целом работает но после перезагрузки страницы, до перезагрузки при запросе handleAddComment я получаю актуальный loginId, но по какой то причине в store комментариев я получаю не актуальный loginId:
const loginId = localStorage.getItem('loginId') || 0; console.log('loginId: ', loginId) // выводит предыдущий id |
const loginId = localStorage.getItem('loginId') || 0; console.log('loginId: ', loginId) // выводит предыдущий id
, а точнее loginId предыдущего пользователя, такое чувство будто localStorage не успел обновить данные в pinia. Где то потерялась реактивность?
Вот код:
spoiler
<template> <div :class="{ 'bg-white': comment.authorId !== productCommentsStore.loginId, 'bg-indigo-100': comment.authorId === productCommentsStore.loginId, 'mr-10': productCommentsStore.loginId && comment.authorId !== productCommentsStore.loginId, 'ml-10': productCommentsStore.loginId && comment.authorId === productCommentsStore.loginId, 'p-4': true, 'shadow-md': true, 'rounded-lg': true, 'mt-4': true, 'relative': true }" @click="productCommentsStore.isEditingComment(comment) ? productCommentsStore.handleClickOutside() : null" > </div> </template> <script setup> import { defineProps } from 'vue'; import { useProductCommentsStore } from '../stores/productComments.js'; import { useModalStore } from '../stores/modal.js'; const modalStore = useModalStore(); const productCommentsStore = useProductCommentsStore(); const props = defineProps({ comment: { type: Object, required: true, }, }) </script> import { ref} from 'vue'; import { defineStore } from 'pinia'; import { useRoute } from 'vue-router'; export const useProductCommentsStore = defineStore('productComments', () => { const comments = ref([]); const commentId = ref(null); const login = localStorage.getItem('login') || ''; const loginId = localStorage.getItem('loginId') || 0; console.log('loginId: ', loginId) //извлекается loginId предыдущего аккаунта const handleAddComment = async (textarea) => { const comment = { authorId: loginId, author: login, productId: productId.value, content: textarea, } const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(comment), }; const response = await fetch('http://localhost:5000/api/comments', requestOptions); if(response.ok) { const createdComment = await response.json(); comments.value.push(createdComment); } } return { comments, commentId, } }) export const useLoginStore = defineStore('login', () => { const handleSubmit = async () => { const login = ref(''); const password = ref(''); const loginData = { login: login.value, password: password.value, } try { const resp = await loginUser(loginData); const token = resp.token; const login = resp.login; const id = resp._id; localStorage.setItem('loginId', id); //записывается правильный loginId из бд } catch (error) { console.error('Error:', error); } } return { login, password, } }) |
<template> <div :class="{ 'bg-white': comment.authorId !== productCommentsStore.loginId, 'bg-indigo-100': comment.authorId === productCommentsStore.loginId, 'mr-10': productCommentsStore.loginId && comment.authorId !== productCommentsStore.loginId, 'ml-10': productCommentsStore.loginId && comment.authorId === productCommentsStore.loginId, 'p-4': true, 'shadow-md': true, 'rounded-lg': true, 'mt-4': true, 'relative': true }" @click="productCommentsStore.isEditingComment(comment) ? productCommentsStore.handleClickOutside() : null" > </div> </template> <script setup> import { defineProps } from 'vue'; import { useProductCommentsStore } from '../stores/productComments.js'; import { useModalStore } from '../stores/modal.js'; const modalStore = useModalStore(); const productCommentsStore = useProductCommentsStore(); const props = defineProps({ comment: { type: Object, required: true, }, }) </script> import { ref} from 'vue'; import { defineStore } from 'pinia'; import { useRoute } from 'vue-router'; export const useProductCommentsStore = defineStore('productComments', () => { const comments = ref([]); const commentId = ref(null); const login = localStorage.getItem('login') || ''; const loginId = localStorage.getItem('loginId') || 0; console.log('loginId: ', loginId) //извлекается loginId предыдущего аккаунта const handleAddComment = async (textarea) => { const comment = { authorId: loginId, author: login, productId: productId.value, content: textarea, } const requestOptions = { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(comment), }; const response = await fetch('http://localhost:5000/api/comments', requestOptions); if(response.ok) { const createdComment = await response.json(); comments.value.push(createdComment); } } return { comments, commentId, } }) export const useLoginStore = defineStore('login', () => { const handleSubmit = async () => { const login = ref(''); const password = ref(''); const loginData = { login: login.value, password: password.value, } try { const resp = await loginUser(loginData); const token = resp.token; const login = resp.login; const id = resp._id; localStorage.setItem('loginId', id); //записывается правильный loginId из бд } catch (error) { console.error('Error:', error); } } return { login, password, } })
Дополнительно:
Решил проблему, я так понял что суть была в рассинхроне данных между двумя сторами. Решил таким образом:
spoiler
export const useLoginStore = defineStore('login', () => { const productCommentsStore = useProductCommentsStore(); const updateLoginId = (newLoginId) => { productCommentsStore.setLoginId(newLoginId);// передача id другому стору }; const handleSubmit = async () => { const loginData = { login: login.value, password: password.value, } try { const resp = await loginUser(loginData); const token = resp.token; const login = resp.login; const id = resp._id; localStorage.setItem('loginId', id); updateLoginId(id); respAuthMessage.value = resp; updateAuthentication(token, login); if(isAuthenticated.value) { router.push('/'); } } catch (error) { console.error('Error:', error); } } return { ... } }) //-------// export const useProductCommentsStore = defineStore('productComments', () => { const loginId = ref(localStorage.getItem('loginId') || null); const setLoginId = (newLoginId) => { loginId.value = newLoginId; //присваивание актуального id }; return { setLoginId } }) |
export const useLoginStore = defineStore('login', () => { const productCommentsStore = useProductCommentsStore(); const updateLoginId = (newLoginId) => { productCommentsStore.setLoginId(newLoginId);// передача id другому стору }; const handleSubmit = async () => { const loginData = { login: login.value, password: password.value, } try { const resp = await loginUser(loginData); const token = resp.token; const login = resp.login; const id = resp._id; localStorage.setItem('loginId', id); updateLoginId(id); respAuthMessage.value = resp; updateAuthentication(token, login); if(isAuthenticated.value) { router.push('/'); } } catch (error) { console.error('Error:', error); } } return { ... } }) //-------// export const useProductCommentsStore = defineStore('productComments', () => { const loginId = ref(localStorage.getItem('loginId') || null); const setLoginId = (newLoginId) => { loginId.value = newLoginId; //присваивание актуального id }; return { setLoginId } })
Ответы:
Вы в курсе, что в localStorage можно только строки хранить? Если у комментария id числовой, то сравнивая с ID из localStorage будет всегда false.
localStorage.setItem('loginId', 123); // Записываем число localStorage.getItem('loginId'); // А получаем внезапно строку "123" )) |
localStorage.setItem('loginId', 123); // Записываем число localStorage.getItem('loginId'); // А получаем внезапно строку "123" ))
- id пользователя из запроса приходит как string, и при getItem я получаю тоже string. Я даже перепроверил.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для решения проблемы синхронизации id пользователя в Pinia при обновлении localStorage после аутентификации, вам следует использовать слушатели событий в Pinia.
Прежде всего, убедитесь, что вы импортировали Pinia и создали экземпляр хранилища. Затем вы можете добавить слушателя событий, который будет обновлять id пользователя в хранилище Pinia при изменении localStorage.
Пример кода:
import { defineStore } from 'pinia'; const store = defineStore({ id: 'user', state: () => ({ userId: localStorage.getItem('userId') || null, }), actions: { setUserId(userId) { this.userId = userId; localStorage.setItem('userId', userId); }, syncUserId() { const userId = localStorage.getItem('userId'); if (userId !== this.userId) { this.setUserId(userId); } }, }, }); // Добавляем слушателя событий для обновления id пользователя window.addEventListener('storage', () => { store.syncUserId(); });
Этот код создаст хранилище Pinia с состоянием userId, которое будет автоматически синхронизироваться с localStorage. Слушатель событий будет отслеживать изменения в localStorage и обновлять id пользователя в хранилище Pinia.
Таким образом, при каждом обновлении localStorage после аутентификации, id пользователя будет автоматически синхронизироваться с вашим хранилищем Pinia.
Надеюсь, это поможет вам решить проблему синхронизации id пользователя в Pinia после обновления localStorage. Если у вас возникнут дополнительные вопросы, не стесняйтесь задавать.