Search code examples
reactjsreduxredux-thunkdispatch

Dispatch type usage in react redux


In redux actions, when we want to set a value, we use a type to dispatch like this :

dispatch({
    type: SET_LOADER,
    payload: true
})

Where the type: SET_LOADER stored in a different file and export it like below.

export const SET_LOADER = 'SET_LOADER'

And in reducer we will do it like this :

function initialState() {
    return {
        formErr: {},
        isLoading: false
    }
}

export default function (state = initialState(), action) {
    const { type, payload } = action;
    switch (type) {
        case SET_LOADER:
            return {
                ...state,
                isLoading: payload
            }
        default:
            return state
    }
}

So in my application, I have this SET_LOADER type used in different actions and reducers. For example, in authentication, in profile update, when I want to load, I will use this type. So I have this type imported in various places.

I'm not sure if it's okay to use a single type for multipurpose because I noticed now that when I do dispatch, the redux state that get updated is not belonged to the target reducer. The state update is happening at different reducer.

But it's working for the first time dispatch. The next update, it's updating the incorrect redux state. After I refresh the page and try to update again, then it work.


Solution

  • first of all you need to separate your reducer into multiple reducers and then combine them in the store , then you can probably get away by using that same action in multiple cases for but then it'll be only a per reeducer solution meaning that let's say you have and Auth reducer this reducer will have its isLoading , and it may interfere with other actions within that reducer , fore example FetchAllProducts will use isLoading but also FetchByIdProduct is using isLoading and same for other actions that will trigger a loading state .

    let's consider these reducers which use the same initial state

    function initialState() {
        return {
            formErr: {},
            isLoading: false
        }
    }
    
    export const authReducer=(state = initialState(), action)=> {
        const { type, payload } = action;
        switch (type) {
            case SET_LOADER:
                return {
                    ...state,
                    isLoading: payload
                }
            default:
                return state
        }
    }
    export const productsReducer=(state = initialState(), action)=> {
        const { type, payload } = action;
        switch (type) {
            case SET_LOADER:
                return {
                    ...state,
                    isLoading: payload
                }
            default:
                return state
        }
    }
    export const cartReducer =(state = initialState(), action)=> {
        const { type, payload } = action;
        switch (type) {
            case SET_LOADER:
                return {
                    ...state,
                    isLoading: payload
                }
            default:
                return state
        }
    }
    
    //this is the store 
    import {createStore,applyMiddleware,compose,combineReducers} from 'redux'
    import thunk from 'redux-thunk'
    import {productsReducer} from './reducers/ProductReducer'
    import {cartReducer} from './reducers/CartReducer'
    import {authReducer } from './reducers/AuthReducer'
    
    
    const initialState={
        products: {
            formErr: {},
            isLoading: false
        },
        cart: {
            formErr: {},
            isLoading: false
        },
        auth: {
            formErr: {},
            isLoading: false
        }
    }
    
    const composeEnhancer = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__  || compose 
    
    const  store = createStore(combineReducers({
            products: productsReducer,
            cart    : cartReducer ,
            auth    : authReducer,
        }),
        initialState,
        composeEnhancer(applyMiddleware(thunk))
    )
    export default store
    

    even though their using the same initial state you , when you will connect a component to the redux store you have access to three different isLoading :

    export default connect((state)=>({
        isLoading : state.products.isLoading,
        isLoading2: state.authReducer.isLoading,
        isLoading3: state.cart.isLoading,
    }))(Products)
    

    but to be honest I'd rather have make my actions more explicit and case specific something like productsFetchIsLoading , this gives you more control and prevents bugs