Search code examples
reactjsreduxredux-thunk

Creating a createAsyncThunk with userID argument


I am having front-end issues with Redux. The backend API is working correctly with Postman so I know the problem isn't there and for some reason I can't get the data in my Redux store to populate.

It is my first createAsyncThunk passing the userId to the backend so I know the problem is something to do with that. I have a console.log in my backend API that prints the log whenever it is accessed so I can see that it isn't being accessed. In the Redux store I am getting a rejected message so I think it is something to do with that.

Can anyone see anything in my action that looks out of place?

Form useEffect

const userDiveLog = useSelector(state => state.user.userDiveLog);

useEffect(() => {
        dispatch(fetchUserDiveLog(user.userID));
    }, []);

createAsyncThunk

export const fetchUserDiveLogs = createAsyncThunk(
    'diveLog/requireUserData', // action name
    // action expects to be called with the name of the field
    async (userId, userDiveLogList) => {
        // you need to define a function to fetch the data by field name
        const response = await userDiveLogList.fetchById(userId);
        const { data } = response;
        // what we return will be the action payload
        return {
            userDiveLog: data,
            // items: data
        };
    },
// only fetch when needed: https://redux-toolkit.js.org/api/createAsyncThunk#canceling-before-execution
    {
        condition: (userDiveLog, {getState}) => {
            const {userDiveLogs} = getState();
            // check if there is already data by looking at the array length
            if ( userDiveLogs[userDiveLog].length > 0 ) {
                // return false to cancel execution
                return false;
            }
        }
    }
)

service

export const userDiveLogList  = (userId) => {
        return axios.get(API_URL + `userdiveloglist/${userId}`);
    };

reducer

export const userSlice = createSlice({
    name: 'user',
    initialState: {
        dives: [],
        diveSpots: [],
        articles: [],
        userDiveLog: []
    },
    reducers: {
        // picks up the pending action from the thunk
        [fetchUserDiveLogs.pending.type]: (state) => {
            // set didLoadData to prevent unnecessary re-fetching
            state.didLoadData = true;
        },
        // picks up the success action from the thunk
        [fetchUserDiveLogs.fulfilled.type]: (state, action) => {
            // want to replace all lists, there are multiple ways to do this
            // I am returning a new state which overrides any properties
            return {
                ...state,
                ...action.payload
            }
        },

Solution

  • createAsyncThunk only accepts a single argument for your thunks / payload creation callbacks. You're currently declaring that it takes two arguments: (userId, userDiveLogList). You would need to put both of these together into a single object.

    Beyond that, there's really no reason to pass userDiveLogList in as a parameter, unless you're overly concerned about mocking API calls (in which case you could consider using the "extra argument" option for the thunk middleware to inject an API layer). I would just declare that above the call to createAsyncThunk(), or import it from another file, and access it that way.