reactjs - Redux,如何重用reducer/actions?

标签 reactjs redux

我正在尝试创建一个 HOC 或至少减少 reducer/action 的数量。所以我创建了一个 library-reducer 来保存我的所有数据和一个 getItemList 操作来处理每个操作。当从 react componentDidMount() 调用操作时,我将传递一个参数,如(产品、用户等...),此参数将知道要更新哪个 api 和哪个状态(例如:state.library.product)。

想听听你对这个技术的建议,是不是一个好方法?

谢谢

const initialState = {
    contact: {
        tmp_state: { addresses: {} },
        item: null,
        receivedAt: null,
        isFetching: false,
        isError: false,
        list: []
    },
    expense: {
        tmp_state: {},
        item: null,
        receivedAt: null,
        isFetching: false,
        isError: false,
        list: []
    },
    service: {
        tmp_state: {},
        item: null,
        receivedAt: null,
        isFetching: false,
        isError: false,
        list: []
    },

    product: {
        tmp_state: {},
        item: null,
        receivedAt: null,
        isFetching: false,
        isError: false,
        list: []
    }
};

export default (state = initialState, action) => {

    // Init reducer name
    var name =  action.type.split("_").pop().toLowerCase();

    switch (action.type) {
        case `REQUEST_${name.toUpperCase()}`:
            return  { 
                ...state,
                [name]: {
                    ...state[name],
                    isFetching: true,
                },
            }

        case `FAILED_${name.toUpperCase()}`: 
            return {
                ...state,
                [name]: {
                    ...state[name],
                    isFetching: false,
                    isError: true,
                }
            }

        case `RECEIVE_${name.toUpperCase()}`:
            return  { 
                ...state,
                [name]: {
                    ...state[name],
                    isFetching: action.isFetching,
                    list: action.payload,
                    receivedAt: action.receivedAt
                }
            }

        case `GET_${name.toUpperCase()}`: 
            return {
                ...state,
                [name]: {
                    ...state[name],
                    item: action.item,
                    isFetching: action.isFetching,
                }
            }
        case `STATE_${name.toUpperCase()}`: 
            var fieldName = action.payload.fieldName.startsWith('_')
            if(fieldName){
                state[name].tmp_state.addresses = { ...state[name].tmp_state.addresses , [ action.payload.fieldName ] : action.payload.value }
            }else{
                state[name].tmp_state = { ...state[name].tmp_state, [ action.payload.fieldName ] : action.payload.value }
            }
            return {
                ...state,
                [name]: {
                    ...state[name]
                }
            }
            
        case `CREATE_${name.toUpperCase()}`:
            return {
                ...state,
                [name]: {
                    ...state[name],
                    isFetching: action.isFetching,
                    tmp_state: initialState[name].tmp_state,
                    list: [ ...state[name].list, action.item ]
                }
            }
        default:
            return state;
    }
}
  

// manager/src/redux/HOC/getListAction.js


import axios from 'axios';
import { API_ENDPOINT, apiCall } from '../../api/constant'
import { requestData, requestFailed  } from './'

// TMP DATA
// import contacts from '../../FAKE_DATA/contacts.json'

// GET FULL LIST OF CLIENT
export function getItemList( actionType ){

    return dispatch => {

        dispatch(requestData(actionType))

        axios.get(`${API_ENDPOINT}${apiCall(actionType).endPoints.get}`, {
          method: 'GET',
          mode: 'cors',
          headers: {
              'x-access-token': localStorage.getItem('token')
          }
        })
        .then(function (response) { 
            return response.data
        }) 
        .then( res => {
          if(res.success){
              dispatch(receiveItems(actionType, res.payload ))  
              }else{
                dispatch(requestFailed(actionType))
              }
        })              
    }
}

function receiveItems(actionType, items) {
  return {
    type: `RECEIVE_${actionType}`,
    payload: items,
    receivedAt: Date.now()
  }
}

最佳答案

您的代码有效,我认为它没有任何问题。我会做的略有不同。我会将该 reducer 包装在一个函数中,并传递 reducer 将关心的状态切片的名称和初始状态,例如:

const makeReducer = (name, initialState) => (state = initialState, action) => {

    var actionType = name.toUpperCase();

    switch (action.type) {
        case `REQUEST_${actionType}`:
            return  { 
                ...state,
                [name]: {
                    ...state[name],
                    isFetching: true,
                },
            }
        // the rest, replace constants accordingly

}

那么主 reducer 将是:

export default combineReducers({
      contact: makeReducer("contact", initialState.contact),
      expense: makeReducer("expense", initialState.expense),
      service: makeReducer("service", initialState.service),
      product: makeReducer("product", initialState.product)
});

你可以在不同的情况下使用 combineReducers 来重用 reducer 逻辑。

查看 redux 文档:https://redux.js.org/recipes/structuring-reducers/reusing-reducer-logic/

关于reactjs - Redux,如何重用reducer/actions?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52574444/

相关文章:

javascript - 样式不会传递给自定义组件 React Native

javascript - 如何在响应式 div 中缩进由溢出包装引起的每一秒可视行

javascript - ReactJS - TypeError : requests. map 不是函数

javascript - 状态未初始化为初始状态

javascript - HOC import TypeError : Object(. ..) 不是函数

reactjs - this.context.router.push 不起作用

javascript - 无法在 React-Redux 中使用 VictoryBar 绘制条形图

typescript 泛型函数重载

reactjs - react + Redux : Scrolling a DOM element after state change

javascript - 没有/#/无法重新加载 React 页面