I am using Redux and when I send a get request to authenticate user it is working, creating a token in cookies, but in Redux the state is not changing. What am I doing wrong? When reloading the page my token and user data are valid, here are some code samples.
After successful login my state is:
{
"user": {
"isAuthenticated": false
}
}
Yet is should be true
I logged in before useEffect
and it says true, because I have token its correct, so how do I pass it inside useEffect
or when page is opened? I want to toast when it is true.
User reducer:
import { createReducer } from "@reduxjs/toolkit"
const initialState = {
isAuthenticated: false,
}
export const userReducer = createReducer(initialState, (builder) => {
builder
.addCase('AuthenticateUserRequest', (state) => {
state.loading = true
})
.addCase('AuthenticateUserSuccess', (state, action) => {
state.isAuthenticated = true
state.user = action.payload
state.loading = false
})
.addCase('AuthenticateUserFailure', (state, action) => {
state.isAuthenticated = false
state.error = action.payload
state.loading = false
})
.addCase('ClearErrors', (state) => {
state.error = null
})
})
User action:
import axios from "axios"
import { authenticateUserUrl } from '../../constants'
export const authenticateUser = () => async (dispatch) => {
try {
dispatch({
type: 'AuthenticateUserRequest'
})
const { data } = await axios.get(authenticateUserUrl, { withCredentials: true })
dispatch({
type: 'AuthenticateUserSuccess',
payload: data.user,
})
} catch (err) {
dispatch({
type: 'AuthenticateUserFailure',
payload: err.response.data.message
})
}
}
store:
import { configureStore } from "@reduxjs/toolkit"
import { userReducer } from "./reducers/user"
const Store = configureStore({
reducer: {
user: userReducer,
},
})
export default Store
app:
import { useContext, useEffect } from "react"
import { authenticateUser } from "./redux/actions/user"
const App = () => {
var store = useContext(ReactReduxContext).store.getState()
useEffect(() => {
Store.dispatch(authenticateUser)
console.log(JSON.stringify(store))
})
3
Answers
Well turns out the solution is:
Issue
The issue here is that of a stale Javascript closure. Redux state updates are synchronous, but you are attempting to console log the
store
value from the render cycle prior to the effect running.Solution
You can access the
store
using theuseStore
hook and then access the current state value in the effect callback.Using the
useStore
hook anddispatch
andgetState
methods are not the normal way of accessing the store in a React component. It’s far more common to use theuseDispatch
anduseSelector
hooks to dispatch actions to the store and subscribe to changes from the store. Use a separate effect to log the user state when it updates.Example:
Solution
Use Use Selector to grab updated values