React redux 中的调度类型用法

Dispatch type usage in react redux

在 redux actions 中,当我们想要设置一个值时,我们使用一个类型来派发这样的:

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

其中 type: SET_LOADER 存储在不同的文件中并导出如下。

export const SET_LOADER = 'SET_LOADER'

在 reducer 中我们会这样做:

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
    }
}

所以在我的应用程序中,我将这种 SET_LOADER 类型用于不同的操作和缩减器。比如在认证的时候,在profile更新的时候,我要加载的时候,我就用这个类型。所以我在各个地方都导入了这种类型。

我不确定是否可以将单一类型用于多用途,因为我现在注意到,当我进行分派时,更新的 redux 状态不属于目标 reducer。状态更新发生在不同的减速器上。

但它是第一次派送。下一次更新,它更新了不正确的 redux 状态。我刷新页面后再次尝试更新,然后就可以了。

首先你需要将你的 reducer 分成多个 reducer,然后将它们组合到 store 中,然后你可能可以通过在多种情况下使用相同的操作来逃脱,但它只会是每个 reeducer解决方案意味着假设你有 Auth reducer 这个 reducer 将有它的 isLoading ,它可能会干扰该 reducer 内的其他动作,例如 FetchAllProducts 将使用 isLoading 但也 FetchByIdProduct 正在使用 isLoading 并且对于将触发加载状态的其他操作也是如此。

让我们考虑这些使用相同初始状态的减速器

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

即使他们使用与您相同的初始状态,当您将组件连接到 redux 存储时,您也可以访问三个不同的 isLoading :

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

但老实说,我宁愿让我的行为更加明确和针对具体情况,比如 productsFetchIsLoading ,这给了你更多的控制权并防止错误

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.

每个动作都被分派到每个减速器。当您调用 dispatch({ type: SET_LOADER, payload: true }) 时,预期的行为是 isLoading 状态将在每个具有 case SET_LOADER.

的减速器中设置为 true

如果您希望加载状态是独立的,那么每个减速器都需要一个唯一的 string 动作类型。


如果您有多个类似的 reducer,那么您可以使用工厂函数来生成类型名称、action creator 函数和 reducer case。在这里,我们从 Redux Toolkit 扩展 createSlice 实用程序。

我们传入 name 这是自动生成的操作类型的前缀,initialState 只是这个 reducer 状态的唯一属性,以及任何唯一的 reducer cases。这将与标准基础状态合并。

助手:

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,
    }
  });
}

用法:

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;

这些动作创建者将创建带有前缀 type 的动作,例如 'profile/setLoader'