пишу социальную сеть на react nodejs, когда захожу в аккаунт в sessionStorage формируется токен,при каждой перезагрузке токен изменяется на рандомную строку. По этому токену запрашиваю из базы, скажем, друзей.Столкнулся с такой проблемой, http запрос происходит до изменения или формирования токена по этому из базы не получаю желаемые данные. Как понимаю нужно организовать асинхронность, пробовал при помощи async/await но не получилось, не понимаю как нужно реализовать задачу
//компонент
function FriendComponent(props) {
const [load, setLoad] = useState(true)
useEffect(()=>{
if(load == true){
let key = sessionStorage.currentUser
//обновляю токен во время перезагрузки
props.dispatch(loadProfile(key,props.history))
//загружаю полученные данные из базы
props.dispatch( updateFriends())
setLoad(false)
}
})
Правильно ли я понял, что проблема в том, что updateFriends()
происходит раньше, чем приходит ответ от loadProfile()
?
А также, если есть возможность приложить ссылку на репозиторий, сделай, пожалуйста. Больше контекста - всегда хорошо.
Да всё правильно, запрос проходит раньше чем обновление токена,
вот ссылка на репу https://bitbucket.org/overlord9600/social-version2/src/master/
а это диаграмма базы
Итак, смотри что там происходит:
loadProfile(key,props.history)
- это обычный экшен, который ничего не знает об асинхронности, он просто отправляет экшен в редюсер, который потом отправляет запрос через axios.
Простой способ решить проблему: добавить в твой store какой-нибудь флаг, который будет следить за тем, что профиль загрузился, и только после этого запускать updateFriend()
.
useEffect(()=>{
if(load){
let key = sessionStorage.currentUser
props.dispatch(loadProfile(key,props.history))
if (isProfileLoaded) { // вынимаем значение из стора
props.dispatch( updateFriends())
setLoad(false)
}
}
}, [load, isProfileLoaded])
*обрати внимание на массив зависимостей
Правильный способ - прикрутить какой-нибудь thunk или redux-promise-middleware, который, собственно, для этого и предназначен. Тогда твой экшен будет возвращать Promise и ты сможешь их складывать в цепочку, ну или комбинировать с предыдущим способом:
useEffect(()=>{
if(load){
let key = sessionStorage.currentUser
props.dispatch(loadProfile(key,props.history))
.then(() => {
props.dispatch( updateFriends())
setLoad(false)
});
}
}, [load, isProfileLoaded])
Третий способ - создать отдельный экшен, который будет выстреливать предыдущие два по очереди.
Bonus point:
- у тебя все запросы отправляются из редюсера. Я не могу сказать, что это прям антипаттерн, но это точно будет неудобно тестировать.
- Должен ли token жить в таблице user? А если пользователь хочет залогиниться одновременно с компьютера и телефона?
2 лайка
спасибо большое за ответ и за советы. мне это очень помогло
1 лайк