【问题标题】:Dispatch type usage in react reduxreact redux 中的调度类型使用
【发布时间】:2021-07-02 02:55:37
【问题描述】:

在 redux 动作中,当我们想要设置一个值时,我们使用一个类型来调度,如下所示:

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 类型用于不同的操作和减速器。例如,在认证中,在配置文件更新中,当我要加载时,我会使用这种类型。所以我在各个地方都导入了这种类型。

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

但它是第一次调度。下一次更新,它正在更新不正确的 redux 状态。在我刷新页面并尝试再次更新后,它就可以工作了。

【问题讨论】:

  • 每个reducer都会响应每个动作。因此,在调度该操作时,您应该期望在所有减速器中将加载状态设置为 true。

标签: reactjs redux redux-thunk dispatch


【解决方案1】:

首先,您需要将减速器分成多个减速器,然后将它们组合到商店中,然后您可能可以通过在多种情况下使用相同的操作来摆脱困境,但这只是每个减速器的解决方案的含义假设你有并且 Auth reducer 这个 reducer 将有它的 isLoading ,它可能会干扰该 reducer 中的其他操作,例如 FetchAllProducts 将使用 isLoadingFetchByIdProduct 也正在使用 isLoading 和相同对于将触发加载状态的其他操作。

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

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,这样可以让您有更多控制权并防止错误

【讨论】:

  • 实际上我的减速器都在单独的文件中,并像你提到的那样将它们组合在商店中。在每个减速器文件中,我都有我帖子中的初始状态。在页面中,我使用了 useSelector 来获取特定 reducer 中的状态。
  • 您是否还考虑过像我在回答末尾提到的那样进行明确的类型和操作?
  • 我还在尝试。我不在我的应用程序中使用连接。将再次更新。谢谢!
【解决方案2】:

我现在注意到,当我进行调度时,得到更新的 redux 状态不属于目标 reducer。状态更新发生在不同的 reducer。

每个动作都被分派给每个reducer。当您调用dispatch({ type: SET_LOADER, payload: true }) 时,预期的行为是isLoading 状态将在每个具有case SET_LOADER 的reducer 中设置为true

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


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

我们传入name,它是自动生成的动作类型的前缀,initialState 只是这个减速器状态的唯一属性,以及任何唯一的减速器案例。这将与标准基本状态合并。

助手:

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'

【讨论】:

    猜你喜欢
    • 2020-10-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-05-05
    • 2023-03-31
    • 1970-01-01
    • 2018-06-28
    相关资源
    最近更新 更多