简体   繁体   English

反应 redux 中的调度类型用法

[英]Dispatch type usage in react redux

In redux actions, when we want to set a value, we use a type to dispatch like this:在 redux 动作中,当我们想要设置一个值时,我们使用一个类型来调度,如下所示:

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

Where the type: SET_LOADER stored in a different file and export it like below.其中type: SET_LOADER存储在不同的文件中并如下所示导出。

export const SET_LOADER = 'SET_LOADER'

And in reducer we will do it like this:在 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
    }
}

So in my application, I have this SET_LOADER type used in different actions and reducers.所以在我的应用程序中,我在不同的操作和减速器中使用了这个SET_LOADER类型。 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.我不确定是否可以将单一类型用于多用途,因为我现在注意到,当我进行调度时,得到更新的 redux state 不属于目标减速器。 The state update is happening at different reducer. state 更新发生在不同的减速器上。

But it's working for the first time dispatch.但它是第一次调度。 The next update, it's updating the incorrect redux state.下一次更新,它正在更新不正确的 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.首先,您需要将减速器分成多个减速器,然后将它们组合在商店中,然后您可能可以通过在多种情况下使用相同的操作来逃脱,但它只是每个减速器的解决方案,这意味着让我们说你有并且 Auth reducer 这个 reducer 将有它的isLoading ,它可能会干扰该 reducer 中的其他操作,例如FetchAllProducts将使用isLoadingFetchByIdProduct正在使用isLoading并且对于将触发加载 state 的其他操作也是如此。

let's consider these reducers which use the same initial state让我们考虑这些使用相同初始 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 :即使他们使用相同的初始 state 您,当您将组件连接到 redux 商店时,您可以访问三个不同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但老实说,我宁愿让我的操作更加明确和具体案例,比如productsFetchIsLoading ,这样可以让你有更多的控制权并防止错误

I noticed now that when I do dispatch, the redux state that get updated is not belonged to the target reducer.我现在注意到,当我进行调度时,更新的 redux state 不属于目标减速器。 The state update is happening at different reducer. state 更新发生在不同的减速器上。

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 .当您调用dispatch({ type: SET_LOADER, payload: true })时,预期的行为是isLoading state 将在每个具有case SET_LOADER的减速器中设置为true

If you want the loading states to be independent then each reducer needs a unique string action type.如果您希望加载状态是独立的,那么每个 reducer 都需要一个唯一的string操作类型。


If you have multiple similar reducers then you can use a factory function to generate the type names, action creator functions, and reducer cases.如果您有多个类似的减速器,那么您可以使用工厂 function 来生成类型名称、动作创建函数和减速器案例。 Here we are extending the createSlice utility from Redux Toolkit.在这里,我们从 Redux Toolkit 扩展createSlice实用程序。

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.我们传入作为自动生成动作类型前缀的name 、仅此减速器initialState的唯一属性的初始状态以及任何唯一减速器案例。 This will get merged with the standard base state.这将与标准基础 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' .这些动作创建者将创建带有前缀type的动作,例如'profile/setLoader'

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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