0

I recently started looking at redux thunks. It is my understanding it should be used for dealing with async actions or where there's a need to dispatch actions from within other actions. So I've got my store configured such as:

import {applyMiddleware, createStore} from "redux";
import rootReducer from "./rootReducer";
import thunk from "redux-thunk";
import { composeWithDevTools } from 'redux-devtools-extension'; // used by redux-devtools to visualize redux in browser

const store = createStore(rootReducer, composeWithDevTools(
    applyMiddleware(thunk),
    // other store enhancers if any
));

export default store;

My reducer looks like:

const INITIAL_STATE = {
    user: null,
}

export const authReducer = (state = INITIAL_STATE, action) => {
    switch (action.type) {

        case actionTypes.REGISTER_NEW_USER:
            const newUser = action.payload
            return {
                ...state,
                'user': newUser
            }
        default:
            return state;
    }
}

my thunk is the following (notice I commented out the part that makes an async call for simplicity while I just test the functionality of my thunk):

// Thunks
export const registerUser = (userData) => {
    console.log("HERE")
    return async (dispatch) => {
        let user = new User();
        try {
            let newUserData;
            console.log(userData)
            // newUserData = await user.register(userData);
            newUserData = {
                'email': 'asdas@gmail.com',
                'token': '234jk23hjkhaSDASD',
            }
            console.log("here in thunk")
            console.log(newUserData)
            cookie.set("user", newUserData.email);
            cookie.set("token", newUserData.token);
            // dispatch(createNewUser(newUserData));
            dispatch({
                type: actionTypes.REGISTER_NEW_USER,
                payload: newUserData
            })
        } catch(e) {
            console.log(e);
        }

    }
}

and my component:

const dispatch = useDispatch();

    const onSubmit = data => {
        dispatch(registerUser(data));

    }

I've written some tests for these but when executing them, they don't seem to be running the thunk function. The console.log("HERE") statement in registerUser is executed but none of the logs from within the return method are. What am I missing?

Side question and not as important as the previous one: Now that i'm using Thunks, do all my actions need to be a thunk? or is it ok to have a combination of thunks and actions that are always plain js objects where no async processing is required?

Thanks

MrCujo
  • 1,218
  • 3
  • 31
  • 56
  • 1
    Just a side comment. Haven't used redux and thunk ever since the react hooks and newer state management libraries like zustand appeared. So much easier. – SILENT Dec 14 '21 at 02:41
  • General FYI: you are writing a very old style of Redux here. Modern Redux is about a fourth of the code, does not use switch..case reducers, ACTION_TYPES, createStore or connect. I would highly recommend you to look into the official Redux tutorial at https://redux.js.org/tutorials/essentials/part-1-overview-concepts and get up to speed with modern Redux first. That tutorial will also go through things like thunks. – phry Dec 14 '21 at 07:34
  • @SILENT omg, I just replaced redux by Zustand. It's so much straight forward, I love it so far. Thanks for your suggestion – MrCujo Dec 15 '21 at 01:22

1 Answers1

0

It works fine for me.

import { applyMiddleware, combineReducers, createStore } from 'redux';
import thunk from 'redux-thunk';
import { composeWithDevTools } from 'redux-devtools-extension';

const actionTypes = { REGISTER_NEW_USER: 'REGISTER_NEW_USER' };
const INITIAL_STATE = {
  user: null,
};

export const authReducer = (state = INITIAL_STATE, action) => {
  switch (action.type) {
    case actionTypes.REGISTER_NEW_USER:
      const newUser = action.payload;
      return {
        ...state,
        user: newUser,
      };
    default:
      return state;
  }
};

const rootReducer = combineReducers({ auth: authReducer });
const store = createStore(rootReducer, composeWithDevTools(applyMiddleware(thunk)));

const registerUser = () => {
  console.log('HERE');
  return async (dispatch) => {
    try {
      console.log('here in thunk');
      const newUserData = { email: 'asdas@gmail.com', token: '234jk23hjkhaSDASD' };
      dispatch({ type: actionTypes.REGISTER_NEW_USER, payload: newUserData });
    } catch (e) {
      console.log(e);
    }
  };
};

store.subscribe(() => {
  console.log('state:', store.getState());
});
store.dispatch(registerUser());

Execution result:

HERE
here in thunk
state: {
  auth: { user: { email: 'asdas@gmail.com', token: '234jk23hjkhaSDASD' } }
}

The doc Writing Logic with Thunks is clear:

For Redux specifically, "thunks" are a pattern of writing functions with logic inside that can interact with a Redux store's dispatch and getState methods.

Thunks are the standard approach for writing async logic in Redux apps, and are commonly used for data fetching. However, they can be used for a variety of tasks, and can contain both synchronous and asynchronous logic.

You are right, it's ok to have a combination of thunks and actions that are always plain js objects. The plain js object actions are often used for UI actions.

But a better way is to use action creators to create a Flux Standard Actions

Lin Du
  • 88,126
  • 95
  • 281
  • 483