我一直在研究React / Redux应用程序来构建报价。我的州的大致简化看起来像这样:
{
account: { name: 'john doe' },
lineItems:[
{ product: {id: 123, ...}, price: 10, units: 5 },
{ product: {id: 124, ...}, price: 10, units: 5 },
],
modifiers: { couponCode: 'asdf', vip: true }
}
我的减速器会切成这样的东西:
const appReducer = combineReducers<GlobalState>({
account: accountReducer,
lineItems: lineItemReducer,
modifiers: modifersReducer,
});
我刚刚得到了一个要求,我基本上需要能够在一个页面上多次渲染整个应用程序(基本上在一个页面上显示不同帐户的1个或多个引号)。所以单个州现在需要看起来像这样:
{
quotes: {
"0": {
account: { name: 'john doe' },
lineItems:[
{ product: {id: 123, ...}, price: 10, units: 5 },
{ product: {id: 124, ...}, price: 10, units: 5 },
],
modifiers: { couponCode: 'asdf', vip: true }
},
"1": {
account: { name: 'billy jean' },
lineItems:[
{ product: {id: 123, ...}, price: 10, units: 5 },
],
modifiers: { couponCode: '', vip: false }
},
}
}
但很显然,这种新的状态并没有真正与我如何切割减速器有关。此外,似乎我必须重构我的所有行动,以便我知道他们应该操作哪个报价?例如,如果我有这样的动作:
{
type: 'UPDATE_PRICE'
payload: { productId: 123, newPrice: 15 }
}
似乎两个引号上的产品123
都会更新。
也许有一些方法我可以在页面上渲染整个应用程序而无需重构我的整个状态?我不确定我最好的方法是什么,不要求我重写应用程序的大部分内容。
答案 0 :(得分:1)
这应该会给你一个想法。它基本上在另一个内部使用一个减速器。就像在另一个函数体内使用函数一样简单。您也可以在runkit.com上运行它。
const { createStore, combineReducers } from 'redux';
const UPDATE_ACCOUNT = 'app/updat-account';
const ADD_QUOTE = 'quote/add-quote';
const appActions = {
updateAcount: (q_id, a) => ({ type: UPDATE_ACCOUNT, payload: { q_id, name: a }}),
};
const quoteActions = {
addQuote: q_id => ({ type: ADD_QUOTE, payload: q_id }),
};
const accountReducer = (app = {}, action) => {
const { type, payload } = action;
switch (type) {
case UPDATE_ACCOUNT:
return { ...app, name: payload.name }
default:
return app;
}
};
const appReducer = combineReducers({
account: accountReducer,
lineItems: (app ={}, action) => app, // just a placeholder
modifiers: (app ={}, action) => app, // just a placeholder
});
const quoteReducer = (state = {}, action) => {
const { type, payload } = action;
switch (type) {
case ADD_QUOTE:
return { ...state, [payload]: {} };
case UPDATE_ACCOUNT: {
const app = state[payload.q_id];
return app
? { ...state, [payload.q_id]: appReducer(state[payload.q_id], action) }
: state;
}
default:
return state;
}
}
const store = createStore(quoteReducer);
store.dispatch(quoteActions.addQuote(3));
store.dispatch(quoteActions.addQuote(2));
store.dispatch(appActions.updateAcount(3, 'apple'));
store.dispatch(appActions.updateAcount(4, 'orange')); // non-existent quote
store.getState():
/**
{
"2": {},
"3": {
"account": {
"name": "apple"
},
"lineItems": {},
"modifiers": {}
}
}
*/
答案 1 :(得分:1)
我想在这里添加我的具体答案..
基本上我添加了一个新的root reducer作为norbertpy建议。但是,我还必须为每个操作添加一个参数quoteId
,以指定操作源自哪个引用并应该对其进行操作。这是重构中最耗时的部分,因为现在调度操作的每个组件都必须能够访问引用键。
<强>减速强>
const quoteReducer = combineReducers({
account: accountReducer,
lineItems: lineItemReducer,
modifiers: modifersReducer,
});
const rootReducer = (state = {quotes: []}, action) => {
const newQuoteState = quoteReducer(state.quotes[action.quoteId], action);
const newQuotes = {...state.quotes};
newQuotes[action.quoteId] = newQuoteState;
return {...state, ...{quotes: newQuotes}};
};
<强>动作强>
{
type: 'UPDATE_PRICE'
quoteId: '0',
payload: { productId: 123, newPrice: 15 }
}