Reputation: 67
Hey Guys im trying to play around with the redux toolkit and i have a wierd issue i get :
Cannot destructure property 'currentRequestId' of 'getState(...).toys' as it is undefined
vs code tells me that the await before the query is: 'await' has no effect on the type of this expression
The currentRequestId really doesnt show in the store, even tho i set it in the code
i copied the example from their site and modified it, perhaps my axios calls kills it? i can see my call isnt even being executed for some reason.
i dont know how to implement a UserApi like the showed in their example so im using a regular axios call.
My Code:
import React from 'react'
import { createAsyncThunk, createSlice, unwrapResult } from '@reduxjs/toolkit'
import axios from 'axios'
import { useDispatch,useSelector } from 'react-redux'
export const query = createAsyncThunk(
'/api/toys',
async (criteria, { getState, requestId }) => {
const { currentRequestId, loading } = getState().toys
if (loading !== 'pending' || requestId !== currentRequestId) {
return
}
const response = await axios.get('http://localhost:3030/api/toys')
return response.data
}
)
export const ToySlice = createSlice({
name: 'toys',
initialState: {
entities: [],
loading: 'idle',
currentRequestId: undefined,
error: null
},
reducers: {},
extraReducers: {
[query.pending]: (state, action) => {
if (state.loading === 'idle') {
state.loading = 'pending'
state.currentRequestId = action.meta.requestId
}
},
[query.fulfilled]: (state, action) => {
const { requestId } = action.meta
if (state.loading === 'pending' && state.currentRequestId === requestId) {
state.loading = 'idle'
state.entities.push(action.payload)
state.currentRequestId = undefined
}
},
[query.rejected]: (state, action) => {
const { requestId } = action.meta
if (state.loading === 'pending' && state.currentRequestId === requestId) {
state.loading = 'idle'
state.error = action.error
state.currentRequestId = undefined
}
}
}
})
export const Test = () => {
const { toys, loading, error } = useSelector(state => state.test)
const dispatch = useDispatch()
const fetchAllToys = async userId => {
try {
const resultAction = await dispatch(query())
const toys = unwrapResult(resultAction)
console.log("Test -> user", toys)
return toys
} catch (err) {
console.log("UsersComponent -> err", err)
}
}
return(<div>
Hello
<button onClick={()=>fetchAllToys()}>Fetch</button>
</div>)
// render UI here
}
export const selectCount = state => state.counter.value;
export default ToySlice.reducer;
The Store:
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from '../features/counter/counterSlice';
import Test from '../features/Test/test'
export default configureStore({
reducer: {
counter: counterReducer,
test:Test
},
});
Link To Example: https://jsfiddle.net/3xq7Lng2/
The Docs:
https://redux-starter-kit.js.org/api/createAsyncThunk
Upvotes: 2
Views: 8437
Reputation: 67469
Your thunk is trying to access getState().toys.currentRequestId
.
However you don't have a state.toys
key, because you're not passing in a field named toys
to configureStore
. You're defining state.counter
and state.Test
, but there's no state.toys
, so it will be undefined.
I don't know what the file name that has that ToySlice
in it. Based on the imports, I'm assuming that it's actually the file named features/Test/test.js
.
The immediate fix would be to change the store setup code to:
import toysReducer from '../features/Test/test';
export default configureStore({
reducer: {
counter: counterReducer,
toys: toyReducer
},
});
That will result in state.toys
existing.
You'll also need to update your component, which is currently doing useSelector(state => state.test)
, and change it to state => state.toys
.
From there, I'd recommend changing the folder and filename to features/toys/toysSlice.js
and updating the import statements accordingly.
Upvotes: 3