简体   繁体   中英

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.

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

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.

Every action gets dispatched to every reducer. When you call dispatch({ type: SET_LOADER, payload: true }) , the expected behavior is that the isLoading state will get set to true in every reducer which has a case SET_LOADER .

If you want the loading states to be independent then each reducer needs a unique string action type.


If you have multiple similar reducers then you can use a factory function to generate the type names, action creator functions, and reducer cases. Here we are extending the createSlice utility from Redux Toolkit.

We pass in the name which is the prefix for the auto-generated action types, the initialState of just the unique properties for this reducer state, and any unique reducer cases. This will get merged with the standard base state.

Helper:

const createCustomSlice = ({name, initialState = {}, reducers = {}}) => {
  return createSlice({
    name,
    initialState: {
      formErr: {},
      isLoading: false
      ...initialState,
    },
    reducers: {
      setLoader: (state, action) => {
        state.isLoading = action.payload;
      },
      setFormErr: (state, action) => {
        state.formErr = action.payload;
      }
      ...reducers,
    }
  });
}

Usage:

const profileSlice = createCustomSlice({
  name: "profile",
  initialState: {
    username: ""
  },
  reducers: {
    setUsername: (state, action) => {
      state.username = action.payload;
    }
  }
});

// reducer function
const profileReducer = profileSlice.reducer;

// action creator functions
export const { setFormErr, setLoader, setUsername } = profileSlice.actions;

These action creators will create actions with a prefixed type like 'profile/setLoader' .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM