2016-03-11 15 views
21

मैं रेडक्स में गहराई से घोंसला वाले राज्य को बदलने के तरीके के बारे में अपने सिर को लपेटने की कोशिश कर रहा हूं। यह मुझे समझता है कि reducers गठबंधन और उन टुकड़ों के लिए राज्य के प्रथम स्तर के गुणों को बदलने के लिए। जहां मैं इतना स्पष्ट नहीं हूं कि गहराई से घिरा हुआ संपत्ति कैसे बदलूं। आइए दिखाएं कि मेरे पास एक शॉपिंग कार्ट ऐप है। नीचे मेरी स्थिति है:रेडक्स रेड्यूसर - गहराई से घोंसला वाला राज्य बदलना

{ 
    cart: { 
     items: [] 
    }, 
    account: { 
     amountLeft: 100, 
     discounts: { 
     redeemed: [], 
     coupons: { 
      buyOneGetOne: false 
     } 
     } 
    } 
} 

एक उपयोगकर्ता एक कोड में प्रवेश करती है, मान लीजिए कि वे "buyOneGetOne" कूपन का लाभ नहीं कर सकते हैं और उस मान हमेशा सही होना चाहिए। मेरे पास कार्ट के लिए एक reducer है और दूसरे खाते के लिए। एक प्रथम स्तर संपत्ति (जैसे अगर मैं गाड़ी के आइटम समाशोधन किया गया था), मैं अपने कम करने में निम्नलिखित बस करना होगा:

case 'EMPTY_CART': 
    return Object.assign({}, state, {items: []}); 

buyOneGetOne बदलते लिए, तथापि, ऐसा लगता है कि मैं पहली बार एक ऐसा करने के लिए की आवश्यकता होगी लगता है कूपन पर ऑब्जेक्ट.साइन (क्योंकि buyOneGetOne संशोधित किया गया था), फिर छूट पर ऑब्जेक्ट.साइन करना (क्योंकि मैंने कूपन संशोधित किए थे), और फिर अंततः कार्रवाई को उत्सर्जित कर दिया ताकि reducer ऑब्जेक्ट पर ऑब्जेक्ट कर सकता है। खाते में छूट (क्योंकि छूट अब है बदला हुआ)। यह वास्तव में जटिल और गलत करने में आसान लगता है, हालांकि, मुझे विश्वास है कि वहां एक बेहतर तरीका होना चाहिए।

क्या मैं यह सब गलत कर रहा हूं? ऐसा लगता है जैसे रेड्यूसर का उपयोग केवल राज्य के रूट स्तर गुणों (जैसे कार्ट और खाते) को संशोधित करने के लिए किया जाता है और मुझे एक रेड्यूसर नहीं होना चाहिए जो खाते के अंदर राज्य को छूता है (जैसे डिस्काउंट रेड्यूसर), क्योंकि खाते में पहले से ही एक reducer है । लेकिन जब मैं केवल राज्य के पेड़ से एक संपत्ति को बदलना चाहता हूं, तो यह ऑब्जेक्ट श्रृंखला को रूट के बच्चे को ऑब्जेक्ट चेन तक हर तरह से बदलने के लिए जटिल हो जाता है ...

क्या आप/क्या आप reducers के अंदर reducers है, इस मामले में एक छूट reducer है?

उत्तर

25

आप निश्चित रूप से reducers के अंदर reducers हो सकता है; वास्तव में, रेडक्स डेमो ऐप यह करता है: http://redux.js.org/docs/basics/Reducers.html

उदाहरण के लिए, आप एक नेस्टेड कम करने `छूट 'नामक बना सकता है:

function discounts(state, action) { 
    switch (action.type) { 
     case ADD_DISCOUNT: 
      return state.concat([action.payload]); 

     // etc etc 
    } 
} 

और फिर आपके अकाउंट कम करने में यह कम करने का इस्तेमाल करते हैं:

function account(state, action) { 
    switch (action.type) { 
     case ADD_DISCOUNT: 
      return { 
       ...state, 
       discounts: discounts(state.discounts, action) 
      }; 

     // etc etc 
    } 
} 

जानने के लिए और, दान द्वारा egghead.io redux series देखें, विशेष रूप से reducer composition वीडियो!

+1

अरे, कुछ सेकंड तक मुझे हराया - महान जवाब हालांकि! – mxstbr

+7

वास्तव में, आप अपने ऐप में एक से अधिक बार 'combineReducers() 'का उपयोग कर सकते हैं। मैं आपको रेडक्स रेपो में [शॉपिंग कार्ट] (https://github.com/reactjs/redux/tree/master/examples/shopping-cart/reducers) उदाहरण देखने के लिए अनुशंसा करता हूं जो रेड्यूसर संरचना के विभिन्न पैटर्न प्रदर्शित करता है। –

+3

यह अच्छा है, मुझे इसका एहसास नहीं हुआ। हालांकि, लक्ष्य के रूप में एक राज्य पेड़ जितना संभव हो उतना लक्ष्य नहीं है? नेस्टेड रेड्यूसर और एक फ्लैट राज्य के पेड़ के बीच संतुलन कहां है? – Skitterm

3

आपको चाहिए प्रत्येक स्तर गहरी के लिए घोंसला combinedReducers

0

हाँ, उन reducers को अलग करने के लिए एक सही बात है। असल में, यदि आप डरते हैं कि उनमें से कुछ कार्यों को अन्य reducer के परिवर्तन की आवश्यकता होगी, तो आप या तो अन्य स्थिरता पर प्रतिक्रिया कर सकते हैं, या बस एक और कार्रवाई भेज सकते हैं।

I've created a library इस समस्या को हल करने के लिए - आसान संरचना की अनुमति देने के लिए, और विलय परिणाम के साथ वर्बोज सिंटैक्स से बचने के लिए। तो, अपने उदाहरण है कि तरह दिखेगा:

import { createTile, createSyncTile } from 'redux-tiles'; 

const cartItems = createSyncTile({ 
    type: ['account', 'cart'], 
    fn: ({ params }) => ({ items: params.items }) 
}); 

const coupons = createSyncTile({ 
    type: ['account', 'coupons'], 
    fn: ({ params }) => params, 
}); 

const reedemedCoupons = createSyncTile({ 
    type: ['account', 'reedemedCoupons'], 
    fn: ({ params }) => params.coupons 
}); 

const account = createTile({ 
    type: ['account', 'info'], 
    fn: ({ api }) => api.get('/client/info') 
}); 

इस रणनीति प्रत्येक घटक परमाणु है का उपयोग करना, और आप आसानी से नए और प्रेषण दूसरों बना सकते हैं, दूसरों को प्रभावित किए बिना, यह यह आसान refactor और में कुछ कार्यक्षमता को दूर करने के लिए बनाता है भविष्य, जब आपकी "टाइल्स" एक जिम्मेदारी सिद्धांत का पालन कर रही हैं।

संबंधित मुद्दे