János
János

Reputation: 35038

How to save response to localStore with Redux Thunk?

  1. They propose to use subscribe for vanilla Redux here:

Where to write to localStorage in a Redux app?

  1. Here for Redux Toolkit he propose to sort out local storage write operation in a separate thunk, and make dispatch from one reducer to the thunk.

How to subscribe to state outside React component in Redux Toolkit?

What do you think?

Right now I have this simple solution, one reducer, it saves to state and to localStore also, I do not face any issue yet. Shall I change?

    extraReducers: (builder) => {
        builder
            .addCase(me.fulfilled, (state, { payload }) => {
                state.authnRes = payload
                localStorage.setItem('authnRes', JSON.stringify(payload))
            })

Shall I make a separate thunk, and move the localStorage.setItem('authnRes', JSON.stringify(payload)) into there?

He says:

Reducer is never an appropriate place to do this because reducers should be pure and have no side effects.


Do you see any drawback in this approach? Thunk fires an other thunk with local store operation.

export const loginEmail = createAsyncThunk(
    `${namespace}/loginEmail`,
    async (req: any, { dispatch }) => {
        const { data } = await axios(req).then((res) => {
            dispatch(persistAuthnUser(res.data)) // <--- here
            return res
        })
        return data
    }
)

and here persist happens:

export const persistAuthnUser = createAsyncThunk(
    `${namespace}/persistAuthnUser`,
    async (data: any, { dispatch }) => {
        return Promise.resolve().then(function () {
            localStorage.setItem('authnRes', JSON.stringify(data))
        })
    }
)

Upvotes: 0

Views: 636

Answers (1)

Rashomon
Rashomon

Reputation: 6762

I managed to make it work implementing a middleware:

import {
  isAsyncThunkAction,
  isPending,
  isRejected,
  isFulfilled,
  isAnyOf,
  createListenerMiddleware,
} from '@reduxjs/toolkit'


const sessionListenerMiddleware = createListenerMiddleware()

sessionListenerMiddleware.startListening({
  matcher: isAnyOf(isAsyncThunkAction(me)), // execute middleware every time "me" is dispatched
  effect: (action, listenerApi) => {
    // listenerApi.getState() // You can also access state using this function

    const shouldSaveSession = isFulfilled(me) // save session every time async thunk "me" is fulfilled

    if (shouldSaveSession(action)) {
      // Middleware is executed after reducer, so we can assume state is already updated
      localStorage.setItem('authnRes', JSON.stringify(action.payload))
    }
  },
})

export const sessionMiddleware = sessionListenerMiddleware.middleware

Dont forget to add the middleware to your store:

export const store = configureStore({
  reducer,
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware()
      .concat(otherMiddlewareYouMightHave)
      .concat(sessionMiddleware), // concat it here
})

Upvotes: 0

Related Questions