我正在尝试创建HOC或至少减少reducer / action的数量。因此,我创建了一个库缩减程序来保存我的所有数据,并创建一个getItemList操作来处理每个操作。当从react componentDidMount()调用动作时,我将传递一个类似(product,user等...)的参数,该参数将知道要更新哪个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()
}
}
答案 0 :(得分:2)
您的代码有效,我认为它没有错。我会做些不同。我会将该减速器包装在一个函数中,并传递减速器将关心的状态片的名称和初始状态,例如:
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
}
那么主要的减速器将是:
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/structuringreducers/reusingreducerlogic。
答案 1 :(得分:1)
将化简器拆分为baseReducer
-我们要重用的化简器,以及default
-将baseReducer
应用于每个状态片的化简器。
class BaseState {
tmp_state = {};
item = null;
receivedAt = null;
isFetching = false;
isError = false;
list = []
}
export const baseReducer = (state = new BaseState(), action) => {
switch (action.payload.subtype) {
case `REQUEST`:
return {
...state,
isFetching: true,
}
case `FAILED`: /* code */
case `RECEIVE`: /* code */
case `GET`: /* code */
case `STATE`: /* code */
case `CREATE`: /* code */
default: /* code */
}
}
class InitialState = {
contact = new BaseState();
expense = new BaseState();
service = new BaseState();
product = new BaseState();
}
export default (state = new InitialState(), action) => {
switch (action.type) {
case 'CONTACT':
return {
...state,
contact: baseReducer(state.contact, action)
}
case 'EXPENSE': /* the same */
case 'SERVICE': /* the same */
case 'PRODUCT': /* the same */
default: return state;
}
}
如果我们有很多项目,我们可以进一步归纳default
减速器。
const smartCompose = mapActionTypeToState => (state, action) => {
const stateSlice = mapActionTypeToState[action.type];
if (!stateSlice) return state;
return {
...state,
[stateSlice]: baseReducer(state.contact, action),
}
}
const mapActionTypeToState = {
CONTACT: 'contact',
EXPENSE: 'expense',
SERVICE: 'service',
PRODUCE: 'produce',
};
export const defaultReducer = smartCompose(mapActionTypeToState);