0

I'm trying to save my a token in redux reducer. console.log works just fine, code is running and the token shows up.

when I try to save the result in a variable - async code does not run, and variable remains undefined.

this is my reducer code:

import { generateCSRF } from '../components/System/CSRF';

const csrfReducer = async (state = null, action) => {
    switch(action.type){
        case 'CREATE_CSRF_TOKEN':
            return  (
                async () => {
                    state = await generateCSRF(); // I'm trying to save the returned token in state variable, unsuccesfully.
                }
            );
        default: 
            return (state);
    }
}

export default csrfReducer;

here is my async function:

import { config } from '../../config/global-config';

export const generateCSRF = async () => {
        let fetchGetResponse = await fetch(`${config.api_url}csrf`, {
            method: 'GET',
            headers: {
                Accept: "application/json",
                "Content-Type": "application/json",
            },
            credentials: "include",
            mode: 'cors'
        });
        
        let parsedResponse = await fetchGetResponse.json();
        console.log(parsedResponse.csrfToken) // this line works.
        return parsedResponse.csrfToken;
}
Osher Levy
  • 83
  • 7
  • Does this answer your question? [How do I return the response from an asynchronous call?](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – ggorlen May 09 '21 at 23:29
  • 1
    You can't have an async reducer, that will generate side effects. What you are trying to do can be achieved with Redux-thunk or Redux-sagas. – Baltasar Solanilla May 10 '21 at 02:04

1 Answers1

0

Redux reducer codes that CAN NOT have any side effects, see Reducers Must Not Have Side Effects, they must be pure functions.

Side-effect code, such as API calls, asynchronous code should be placed in action creator, in order to support asynchronous action creator, you need to use redux-thunk middleware.

The complete workflow is:

  1. Dispatch createCsrfToken thunk async action.
  2. Make an API call to get the csrfToken
  3. Dispatch CREATE_CSRF_TOKEN sync action
  4. Handle CREATE_CSRF_TOKEN action in reducer
  5. Get the updated state in promise.then() method.

E.g.

csrfReducer.ts:

const csrfReducer = (state = null, action) => {
  switch (action.type) {
    case 'CREATE_CSRF_TOKEN':
      return action.payload;
    default:
      return state;
  }
};

export default csrfReducer;

actionCreator.ts:

import { generateCSRF } from './api';

export function createCsrfToken() {
  return async (dispatch) => {
    const token = await generateCSRF();
    return dispatch({ type: 'CREATE_CSRF_TOKEN', payload: token });
  };
}

api.ts:

const config = {
  api_url: 'http://localhost:3000/api/',
};

export const generateCSRF = async () => {
  //   let fetchGetResponse = await fetch(`${config.api_url}csrf`, {
  //     method: 'GET',
  //     headers: {
  //       Accept: 'application/json',
  //       'Content-Type': 'application/json',
  //     },
  //     credentials: 'include',
  //     mode: 'cors',
  //   });

  //   let parsedResponse = await fetchGetResponse.json();

  const parsedResponse = {
    csrfToken: 'mocked csrf token',
  };
  return parsedResponse.csrfToken;
};

store.ts:

import { applyMiddleware, createStore } from 'redux';
import thunk from 'redux-thunk';
import csrfReducer from './csrfReducer';

const store = createStore(csrfReducer, applyMiddleware(thunk));
export { store };

main.ts:

import { createCsrfToken } from './actionCreator';
import { store } from './store';

function main() {
  store.dispatch(createCsrfToken() as any).then(() => {
    console.log(store.getState());
  });
}

main();

Output:

mocked csrf token
Lin Du
  • 88,126
  • 95
  • 281
  • 483