I am working with React on the frontend and trying to use Redux with createAsyncThunk to make a api call.
It fetches the data correctly , and can see it with console.log within the ‘extraReducer’ property within the ‘slice’
But to update the state and retrieve the data to the component returns a undefined. The weird thing is that it worked at first but suddenly it doesnt return the updated state
store.js
import { configureStore, applyMiddleware } from "@reduxjs/toolkit"
// import { getAvailableLocations } from "./middleware/locationThunk"
import userSlice from "./features/users/userSlice.jsx"
export const store = configureStore({
reducer: {
users: userSlice
},
devTools: process.env.NODE_ENV === 'development',
trace: true
})
util. js
export const initialUserState = {
first_name: '',
last_name: '',
email: '',
password: '',
location: '',
phone_number: '',
region: '',
data_of_birth: '',
gender: '',
conversion: '',
cityId: null,
city_list: [],
state_id: null,
state_list: [],
// status: 'idle', // | 'loading' | 'succeeded' | 'failed'
// error: null
}
userSlice.js
import initialUserState from './util'
export const getAvailableLocations = createAsyncThunk(
'/api/getLocation',
async (id) => {
try {
let getCities = []
const getStates = await GetState(countryid) // countryid
if(id) getCities = await GetCity(countryid, id)
return { getStates, getCities}
} catch (err) {
console.log({'userSlice.js: - nr.19 - getLocation': err})
return err.message
}
})
const userSlice = createSlice({
name: 'users',
initialState:{user: initialUserState, status: 'idle', error: null},
reducers: {
updateUser: {
modify(state, action) {
// state.user.users
console.log({state, action})
}
},
createUser: {createUser(state, action){
console.log({state, action})
state.user.users.push(action.payload)
},
},
updateProfile(state, action){
console.log({state, action})
},
},
extraReducers: builder => {
builder
.addCase(getAvailableLocations.fulfilled, (state, action) => {
state.status = 'success'
let stateList = action.payload.getStates
let optionStateList = stateList.map((state) => ({
label: state.name,
value: state.id
}))
let cityList = action.payload.getCities
let optionCitiesList = cityList.map((city) => ({
label: city.name,
value: city.id
}))
// console.log({reconstructedStateList: optionStateList, reconstructedCitiesList: optionCitiesList})
// state.user.state_list.push(optionStateList)
// state.user.city_list.push(optionCitiesList)
// state.user.state_list.concat({...optionStateList})
state.user.state_list = {...optionStateList}
state.user.city_list = {...optionCitiesList}
console.log({updated_state: state.user.state_list})
//return action.payload
// console.log({updated_StateList: state.user.state_list, updated_CityList:state.user.city_list})
})
.addCase(getAvailableLocations.pending, (state, action) => {
state.status = 'loading'
})
.addCase(getAvailableLocations.rejected, (state, action)=> {
state.status = 'failed'
state.error = action.error
})
},
selectors: {
selectStateList: (state) => state.user.state_list
}
}
)
const{ selectStateList } = userSlice.selectors
// Extract the action creators object and the reducer
const { actions, reducer } = userSlice
// Extract and export each action creator by name
export {actions, selectStateList} // { createUser, updateUser, editLo }
// Export the reducer, either as a default or named export
export default reducer
component :
import { useSelector, useDispatch } from 'react-redux'
import { getAvailableLocations, selectStateList } from '../../../store/features/users/userSlice.jsx' //, getUserProfile
export const ProfileTabInterface = () => {
const reduxDispatch = useDispatch()
const user = useSelector((state) => state.user)
console.log({reduxUser: user})
console.log({reduxStateList: selectStateList})
if(user?.state_list){
console.log('state list came through?')
const {city_list, state_list} = user
const stateList = state_list
const cityList = city_list
console.log({isEmptyStateList: stateList , isEmptyCityList: cityList})
}
let stateSelected = {id:2612}
let userFinalFormData = {
email: '',
phone_number: ''
}
const getLocations = async (id) => {
await reduxDispatch(getAvailableLocations(id))
// await reduxDispatch(getAvailableLocations(id)).unwrap()
}
useEffect(() => {
// console.log({stateSelected})
getLocations(stateSelected.id)
// reduxDispatch(getAvailableLocations(stateSelected.id))
// reduxDispatch(getUserProfile())
if(user){
const { email, phone_number } = user
userFinalFormData.email = email
userFinalFormData.phone_number = phone_number
Object.entries(userFinalFormData).map(([key, value]) => {
setEnteredInput((prevValues) => ({
...prevValues,
[key]: value
}))
})
}
}, [])
const handleGeneralUserInput = (identifier, value) => {
setEnteredInput((prevValues) => ({
...prevValues,
[identifier]: value
}))
const updateUserForm = {[identifier]: value}
dispatch({type: 'SET_GENERAL_USER_DATA', payload: updateUserForm})
}
const handleStatelUserInput = (identifier, value) => {
console.log({stateEvent: value, identifier})
if(!stateList) return
stateSelected = stateList.find((state) => state.id == Number(value))
handleGeneralUserInput('state_id', stateSelected.id)
handleGeneralUserInput(identifier, stateSelected.name)
reduxDispatch(getAvailableLocations(stateSelected.id))
}
const typeText = 'text'
const typePhone = 'tel'
const typeLocation = 'location'
const InterfaceConfiguration = {
buttonname: 'Save Changes',
setItems : [
{ name: 'Email', id: 'email', type: typeText, placeholder: 'email', value: enteredInput?.email, error: errors.email, invalid: enteredInputIsInvalid.email, autoComplete: 'email', required:true, onChange: (e) => handleGeneralUserInput('email', e.target.value), onBlur : (e) => inputBlurHandle('email', e.target.value, setEnteredInputIsInvalid)},
{ name: 'PhoneNumber', id: 'phone_number', type: typePhone, placeholder: 'phone number', value: enteredInput?.phone_number, error: errors.phone_number, invalid: enteredInputIsInvalid.phone_number, required:true, onChange: (value) => handleGeneralUserInput('phone_number', value), onBlur : (e) => inputBlurHandle('phone_number', e.target.value, setEnteredInputIsInvalid)},
{ name: 'Location', id: 'location', type: typeLocation, value: enteredInput?.city, cityId: enteredInput?.city_id, stateId: enteredInput?.state_id, error: errors?.location, invalid: enteredInputIsInvalid?.city,
required:true , onChangeState: (e) => handleStatelUserInput('state', e.target.value), onChangeCity: (e) => handleCitylUserInput('city', e.target.value), onBlur : (e) => inputBlurHandle('city', e.target.value, setEnteredInputIsInvalid)},
]
}
console.log({enteredInputProfileTab: enteredInput})
return(
<>
<CreateFormInterface array={InterfaceConfiguration.setItems} />
</>
)
App.js
import { Provider } from 'react-redux'
import { store } from './store/index.js'
function App() {
const router = createBrowserRouter([
{
path: '/',
element: <RootLayout />,
errorElement: <ErrorPage />,
id: 'root',
loader: tokenLoader,
children: [
{ path: '/', element: <HomePage /> },
{ path: '/sign-up', element: <SignUpPage />, loader: SignUpLoader },
{ path: '/work', element: <LoginPage /> },
{ path: '/calendar', element: <CalendarPage />, loader: CalendarLoader},
{ path: '/subscribe', element: <OrderPage />},
{ path: '/payment', element: <PaymentPage />},
{ path: '/dashboard/*', element: <DashboardPage />}, //, loader: UserLoader
{ path: '/contact', element: <ContactPage />},
]
}
])
return (
<Provider store={store}>
<ReactQueryClientProvider>
<UserFormContextProvider>
<RouterProvider router={router} ></RouterProvider>
</UserFormContextProvider>
</ReactQueryClientProvider>
</Provider>
)
}
export default App
I have tried using the return ‘type’ to return the updated state, and tried returnnig the payload but not getting the results that I wanted still cannot get the data within the state (updated)