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

उपयोगकर्ता एक कविता चलाता है - उसकी प्रतिभा का आकलन करता है। पद्य की शुरूआत के साथ नियंत्रण को नियंत्रित किया जाता है और प्रत्येक परिवर्तन के लिए मूल्यांकन का पुनर्गणना होता है। एक बटन भी है जिसके द्वारा परिणाम के साथ पाठ रीसेट किया जाता है, और उपयोगकर्ता को एक संदेश प्रदर्शित किया जाता है कि वह शुरुआत से शुरू कर सकता है। इस
धागे में स्रोत कोड।
कोड संगठन:

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

यह कैसे काम करता है:
1. नियंत्रण प्रेषण-निर्माता:
import at from '../constants/actionTypes'; export function poemTextChange(text) { return function (dispatch, getstate) { dispatch({ type: at.POEM_TYPE, payload: text }); }; }
क्रिया प्रकारों की स्थिरांक को एक अलग फ़ाइल में ले जाया जाता है। सबसे पहले, हम टाइपोस से बहुत सुरक्षित हैं। दूसरी बात यह कि हमारे पास इंटेलीजेंस उपलब्ध होगा।
2. इसके बाद reducer की बात आती है।
import logic from '../logic/poem'; export default function poemScoringReducer(state = Immutable.Map(), action) { switch (action.type) { case at.POEM_TYPE: return logic.onType(state, action.payload); default: return state; } }
लॉजिक प्रोसेसिंग को एक अलग
केस फंक्शन में ले जाया जाता है। अन्यथा, reducer कोड जल्दी से अपठनीय हो जाएगा।
3. शाब्दिक विश्लेषण और कृत्रिम बुद्धि का उपयोग करके प्रसंस्करण क्लिक का तर्क:
export default { onType(state, text) { return state .set('poemText', text) .set('score', this.calcScore(text)); }, calcScore(text) { const score = Math.floor(text.length / 10); return score > 5 ? 5 : score; } };
"नई कविता" बटन के मामले में, हमारे पास निम्नलिखित क्रिया-निर्माता हैं:
export function newPoem() { return function (dispatch, getstate) { dispatch({ type: at.POEM_TYPE, payload: '' }); dispatch({ type: appAt.SHOW_MESSAGE, payload: 'You can begin a new poem now!' }); }; }
सबसे पहले, उसी क्रिया को प्रेषण करें जो हमारे पाठ और स्कोर को रीसेट करती है। फिर, कार्रवाई भेजें, जो किसी अन्य reducer द्वारा पकड़ा जाएगा और उपयोगकर्ता को एक संदेश प्रदर्शित करेगा।
सब कुछ सुंदर है। आइए अपने लिए समस्याएँ बनाएँ:
समस्याएं:
हमने अपना आवेदन पोस्ट कर दिया है। लेकिन हमारे उपयोगकर्ता, यह देखते हुए कि उन्हें कविता की रचना करने के लिए कहा गया था, स्वाभाविक रूप से अपने काम को पोस्ट करना शुरू कर दिया, जो कि काव्य भाषा के कॉर्पोरेट मानकों के साथ असंगत है। दूसरे शब्दों में, हमें अश्लील शब्दों को मध्यम करने की आवश्यकता है।
हम क्या करेंगे:
- इनपुट टेक्स्ट में, सभी असंबंधित शब्दों को * सेंसर * से बदलना आवश्यक है
- इसके अलावा, यदि उपयोगकर्ता ने एक गंदा शब्द चलाया है, तो आपको उसे एक संदेश के साथ चेतावनी देने की आवश्यकता है कि वह गलत कर रहा है।
सब ठीक है। हमें केवल शब्दों की गणना करने के लिए, बुरे शब्दों को बदलने के अलावा, पाठ का विश्लेषण करने की आवश्यकता है। समस्या नहीं है। और यह भी, उपयोगकर्ता को सूचित करने के लिए, आपको हमारे द्वारा हटाए गए की एक सूची चाहिए। स्रोत कोड
यहाँ हैहम तर्क के कार्य को रीमेक करते हैं ताकि यह नए राज्य के अलावा, उपयोगकर्ता को संदेश के लिए आवश्यक जानकारी लौटाए (प्रतिस्थापित शब्द):
export default { onType(state, text) { const { reductedText, censoredWords } = this.redactText(text); const newState = state .set('poemText', reductedText) .set('score', this.calcScore(reductedText)); return { newState, censoredWords }; }, calcScore(text) { const score = Math.floor(text.length / 10); return score > 5 ? 5 : score; }, redactText(text) { const result = { reductedText:text }; const censoredWords = []; obscenseWords.forEach((badWord) => { if (result.reductedText.indexOf(badWord) >= 0) { result.reductedText = result.reductedText.replace(badWord, '*censored*'); censoredWords.push(badWord); } }); if (censoredWords.length > 0) { result.censoredWords = censoredWords.join(' ,'); } return result; } };
चलो अब इसे लागू करते हैं। लेकिन कैसे? Reducer में, इसका कोई मतलब नहीं है कि हम इसे कॉल कर सकें, क्योंकि हम राज्य में पाठ और मूल्यांकन करेंगे, लेकिन हमें संदेश के साथ क्या करना चाहिए? संदेश भेजने के लिए, किसी भी स्थिति में, हमें संबंधित कार्रवाई को भेजना होगा। इसलिए, हम एक्शन-क्रिएटर को अंतिम रूप दे रहे हैं।
export function poemTextChange(text) { return function (dispatch, getState) { const globalState = getState(); const scoringStateOld = globalState.get('poemScoring');
यह भी reducer को संशोधित करने के लिए आवश्यक है, क्योंकि यह अब तर्क फ़ंक्शन को कॉल नहीं करता है:
switch (action.type) { case at.POEM_TYPE: return action.payload; default: return state;
क्या हुआ:
और अब, सवाल है। हमें एक reducer की आवश्यकता क्यों है, जो कि अधिकांश भाग के लिए, एक नए राज्य के बजाय केवल पेलोड लौटाएगा? जब अन्य क्रियाएं उस तर्क को कार्रवाई में प्रकट करती हैं, तो क्या नए एक्शन-प्रकार को पंजीकृत करना आवश्यक होगा? या शायद एक सामान्य SET_STATE बनाएं? शायद नहीं, क्योंकि तब, निरीक्षक एक गड़बड़ होगा। तो हम उसी प्रकार के मामले का उत्पादन करेंगे?
समस्या का सार इस प्रकार है। यदि तर्क के प्रसंस्करण में राज्य के एक टुकड़े के साथ काम करना शामिल है, जिसके लिए कई रेड्यूसर जिम्मेदार हैं, तो आपको सभी प्रकार के विकृतियों को लिखना होगा। उदाहरण के लिए, केस-फ़ंक्शंस के मध्यवर्ती परिणाम, जो कई क्रियाओं का उपयोग करके अलग-अलग reducers में बिखरे होने चाहिए।
इसी तरह की स्थिति, यदि केस फ़ंक्शन को आपके रिड्यूसर में क्या है, की तुलना में अधिक जानकारी की आवश्यकता होती है, तो आपको इसके कॉल को एक्शन के लिए करना होगा, जहां वैश्विक राज्य तक पहुंच है, इसके बाद पेलोड के रूप में नया राज्य भेजना है। मॉड्यूल में बहुत सारे तर्क होने पर किसी भी मामले में एक रिड्यूसर को विभाजित करना होगा। और इससे बड़ी असुविधा होती है।
आइए एक तरफ स्थिति को देखें। हमारी कार्रवाई में, हमें वैश्विक स्तर पर एक राज्य मिलता है। इसे
म्यूट करने के लिए आवश्यक है (
GlobalState.get ('poemScoring'); )। यह पता चला है कि हम पहले से ही कार्रवाई में जानते हैं कि काम किस राज्य के साथ चल रहा है। हमारे पास एक नया राज्य है। हम जानते हैं कि इसे कहां रखा जाए। लेकिन हम इसे एक वैश्विक एक में रखने के बजाय, इसे कुछ प्रकार के पाठ के साथ रिड्यूसर के पूरे झरने में चलाते हैं ताकि यह प्रत्येक स्विच-केस से गुजरता है और एक बार प्रतिस्थापन करता है। मुझे इस के अहसास से झुर्रियाँ पड़ती हैं। मैं समझता हूं कि यह विकास में आसानी और कनेक्टिविटी को कम करने के लिए किया जाता है। लेकिन हमारे मामले में, अब इसकी कोई भूमिका नहीं है।
अब, मैं उन सभी बिंदुओं को सूचीबद्ध करूँगा, जो मुझे वर्तमान कार्यान्वयन में पसंद नहीं हैं, अगर इसे असीमित समय के लिए चौड़ाई और गहराई में बढ़ाया जाना है :
- Reducer के बाहर एक राज्य के साथ काम करते समय महत्वपूर्ण असुविधा।
- कोड पृथक्करण की समस्या। हर बार जब हम किसी कार्रवाई को भेजते हैं, तो यह प्रत्येक रिड्यूसर से गुजरता है, प्रत्येक मामले से गुजरता है। जब आपके पास एक छोटा अनुप्रयोग है तो परेशान न करना सुविधाजनक है। लेकिन, अगर आपके पास एक राक्षस है जो कई वर्षों के लिए दर्जनों रेड्यूसर और सैकड़ों मामलों के साथ बनाया गया था, तो मैं इस तरह के दृष्टिकोण की व्यवहार्यता के बारे में सोचना शुरू कर देता हूं। शायद, हजारों मामलों के साथ भी, यह प्रदर्शन पर महत्वपूर्ण प्रभाव नहीं डालेगा। लेकिन, यह समझते हुए कि जब मुद्रण पाठ, प्रत्येक प्रेस सैकड़ों मामलों के माध्यम से एक मार्ग का कारण होगा, तो मैं इसे नहीं छोड़ सकता जैसा कि यह है। कोई भी, सबसे छोटा अंतराल, जिसे अनंत द्वारा गुणा किया जाता है, अनंत में जाता है। दूसरे शब्दों में, यदि आप ऐसी चीजों के बारे में नहीं सोचते हैं, तो जल्दी या बाद में, समस्याएं पैदा होंगी।
विकल्प क्या हैं?
एक। अपने स्वयं के प्रदाताओं के साथ पृथक आवेदन। प्रत्येक मॉड्यूल (उप-अनुप्रयोग) में, आपको राज्य के सामान्य भागों (खाता, संदेश, आदि) की नकल करनी होगी।
ख। प्लग करने योग्य अतुल्यकालिक reducers का उपयोग करें। यह दान द्वारा स्वयं अनुशंसित नहीं है।
सी। रिड्यूसर में एक्शन फिल्टर का उपयोग करें। यही है, प्रत्येक प्रेषण के बारे में जानकारी के साथ होना चाहिए कि यह किस मॉड्यूल को भेजा जा रहा है। और मॉड्यूल के रूट रिड्यूसर में, उपयुक्त परिस्थितियों को लिखें। मैंने कोशिश की है। पहले या बाद में ऐसी अनैच्छिक त्रुटियों की संख्या नहीं थी। कार्रवाई कहां होती है, इसे लेकर लगातार भ्रम की स्थिति है। - हर बार एक कार्रवाई को भेज दिया जाता है, न केवल प्रत्येक रिड्यूसर के लिए एक रन होता है, बल्कि रिवर्स स्टेट का संग्रह भी होता है। इससे कोई फर्क नहीं पड़ता कि राज्य reducer में बदल गया है या नहीं - इसे CombReducers में बदल दिया जाएगा।
- प्रत्येक प्रेषण ताक पर लगाई गई प्रत्येक संलग्न घटक के लिए mapStateToProps को संसाधित करता है जो पृष्ठ पर मुहिम की जाती है। यदि हम रिड्यूसर को विभाजित करते हैं, तो हमें डिस्पैच को विभाजित करना होगा। क्या यह महत्वपूर्ण है कि हमारे पास एक बटन है जो पाठ को अधिलेखित करता है और विभिन्न प्रेषण के साथ संदेश प्रदर्शित करता है? शायद नहीं। लेकिन मेरे पास अनुकूलन अनुभव है, जब 15 से 3 तक डिस्पैच की संख्या को कम करने की अनुमति देता है, जो कि संसाधित व्यापार तर्क की समान मात्रा के साथ, सिस्टम की प्रतिक्रिया को बढ़ाने की अनुमति देता है। मुझे पता है कि पुस्तकालय हैं जो एक बैच में कई डिस्पैच को जोड़ सकते हैं, लेकिन यह बैसाखी का उपयोग करके जांच के साथ संघर्ष है।
- कुचलते समय, यह देखना कभी-कभी बहुत मुश्किल होता है कि क्या हो रहा है। कोई एक जगह नहीं है, सब कुछ अलग-अलग फाइलों पर बिखरा हुआ है। यह खोज करना आवश्यक है कि सभी स्रोत कोड में स्थिरांक की खोज करके प्रसंस्करण कहाँ लागू किया जाता है।
- उपरोक्त कोड में, घटक और कार्य सीधे वैश्विक स्थिति तक पहुँचते हैं:
const userName = globalState.getIn(['app', 'account', 'name']); … const text = state.getIn(['poemScoring', 'poemText']);
यह कई कारणों से अच्छा नहीं है:
एक। मॉड्यूल को आदर्श रूप से पृथक किया जाना चाहिए। उन्हें यह जानने की जरूरत नहीं है कि वे किस राज्य में रहते हैं।
ख। अलग-अलग स्थानों पर समान पथों का उल्लेख अक्सर त्रुटियों / टाइपो के साथ न केवल किया जाता है, बल्कि वैश्विक राज्य के विन्यास में परिवर्तन या इसे संग्रहीत करने के तरीके में परिवर्तन की स्थिति में भी अत्यंत कठिन बना देता है।
- नई कार्रवाई लिखते समय, मुझे यह आभास था कि मैं कोड के लिए कोड लिख रहा था। मान लीजिए हम पेज में एक चेक बॉक्स जोड़ना चाहते हैं और कहानी में इसकी बूलियन स्थिति को दर्शाते हैं। यदि हम कार्रवाई / पुनर्विकास का एक समान संगठन चाहते हैं, तो हमें निम्न करना होगा:
- पंजीकरण क्रिया-प्रकार स्थिर
- एक्शन क्रेटर लिखें
- नियंत्रण में, इसे आयात करें और इसे mapDispatchToProps में पंजीकृत करें
- PropTypes में रजिस्टर करें
- नियंत्रण में एक हैंडलचेकबॉक्स बनाएं और इसे चेक बॉक्स में निर्दिष्ट करें
- केस फ़ंक्शन कॉल के साथ रिड्यूसर में एक स्विच जोड़ें
- लॉजिक में केस फंक्शन लिखें
एक मुक्केबाजी की जांच के लिए! - संयोजनरेड्यूसर के साथ उत्पन्न होने वाली स्थिति स्थिर है। इससे कोई फर्क नहीं पड़ता कि आपने मॉड्यूल बी में प्रवेश किया है या नहीं, यह टुकड़ा कहानी में होगा। खाली है, लेकिन होगा। इंस्पेक्टर का उपयोग करना सुविधाजनक नहीं है जब स्टेप में बहुत सारे अप्रयुक्त खाली नोड्स होते हैं।
हम ऊपर वर्णित कुछ समस्याओं को हल करने का प्रयास करते हैं
इसलिए, हमें बेवकूफ रेड्यूसर मिला, और एक्शन-क्रेटर्स / लॉजिक में हम गहराई से एम्बेडेड अपरिवर्तनीय - संरचनाओं के साथ काम करने के लिए कोड के फुटपीस लिखते हैं। इससे छुटकारा पाने के लिए, मैं पदानुक्रमित चयनकर्ताओं के तंत्र का उपयोग करता हूं, जो न केवल राज्य के वांछित टुकड़े तक पहुंच की अनुमति देता है, बल्कि इसे (सुविधाजनक सेटइन) भी बदल देता है। मैंने इसे
अपरिवर्तनीय-चयनकर्ताओं पैकेज में प्रकाशित किया।
आइए हमारे उदाहरण देखें कि यह कैसे काम करता है (
रिपॉजिटरी ):
कविता मॉड्यूल में, हम चयनकर्ताओं वस्तु का वर्णन करते हैं। हम उन क्षेत्रों का वर्णन करते हैं, जहां से हम सीधे पढ़ना / लिखना चाहते हैं। संग्रह के तत्वों तक पहुंचने के लिए किसी भी घोंसले के शिकार और मापदंडों की अनुमति है। हमारे लेख में सभी संभावित क्षेत्रों का वर्णन करना आवश्यक नहीं है।
import extendSelectors from 'immutable-selectors'; const selectors = { poemText:{}, score:{} }; extendSelectors(selectors, [ 'poemScoring' ]); export default selectors;
इसके अलावा, विस्तारकर्ता विधि हमारी वस्तु के प्रत्येक क्षेत्र को चयनकर्ता फ़ंक्शन में बदल देती है। दूसरा पैरामीटर राज्य के उस हिस्से को पथ को इंगित करता है जिसे चयनकर्ता नियंत्रित करता है। हम एक नई वस्तु नहीं बनाते हैं, लेकिन वर्तमान को बदल देते हैं। यह हमें वर्किंग इंटेलिजेंस के रूप में एक बोनस देता है:

हमारा उद्देश्य क्या है - इसके विस्तार के बाद एक चयनकर्ता:
Selectors.poemText (राज्य) फ़ंक्शन केवल
state.getIn (['poemScoring', 'poemText']) निष्पादित करता है।
फंक्शन
रूट (अवस्था) - 'कविता कोश' हो जाता है।
प्रत्येक चयनकर्ता का अपना स्वयं का
बदला हुआ फ़ंक्शन
(GlobalState, newPart) है , जो setIn के माध्यम से एक नए वैश्विक राज्य को देता है, जिसके स्थान पर उसी हिस्से को प्रतिस्थापित किया जाता है।
इसके अलावा, एक
फ्लैट ऑब्जेक्ट जोड़ा जाता है जिसमें सभी अद्वितीय चयनकर्ता कुंजियों को डुप्लिकेट किया जाता है। यही है, अगर हम फॉर्म की गहरी स्थिति का उपयोग करते हैं
selectors = { dive:{ in:{ to:{ the:{ deep:{} } } } }}
आप
selectors.dive.in.to.the.deep (राज्य) या
selectors.flat.deep (राज्य) के रूप में गहरे
उतर सकते हैं।
आगे बढ़ो। हमें नियंत्रण में डेटा अधिग्रहण को अद्यतन करने की आवश्यकता है:
कविता:
function mapStateToProps(state, ownprops) { return { text:selectors.poemText(state) || '' }; }
स्कोर:
function mapStateToProps(state, ownprops) { const score = selectors.score(state); return { score }; }
अगला, रूट रिड्यूसर बदलें:
import initialState from './initialState'; function setStateReducer(state = initialState, action) { if (action.setState) { return action.setState; } else { return state;
यदि वांछित है, तो हम CombReducers का उपयोग करके गठबंधन कर सकते हैं।
कार्रवाई गड्ढा, उदाहरण के लिए, poemTextChange:
export function poemTextChange(text) { return function (dispatch, getState) { dispatch({ type: 'Poem typing', setState: logic.onType(getState(), text), payload: text }); }; }
हम अब एक्शन-टाइप स्थिरांक का उपयोग नहीं कर सकते हैं, क्योंकि अब केवल निरीक्षक में दृश्य के लिए टाइप का उपयोग किया जाता है। हम परियोजना में रूसी में कार्रवाई का पूर्ण-पाठ विवरण लिखते हैं। आप पेलोड से छुटकारा भी पा सकते हैं, लेकिन मैं इसे बचाने की कोशिश करता हूं ताकि इंस्पेक्टर में, यदि आवश्यक हो, तो मैं समझता हूं कि कार्रवाई को किन मापदंडों के साथ बुलाया गया था।
और, वास्तव में, तर्क ही:
onType(gState, text) { const { reductedText, censoredWords } = this.redactText(text); const poemState = selectors.root(gState) || Immutable.Map();
उसी समय,
संदेश.शो मेसेजेज को पड़ोसी मॉड्यूल के तर्क से आयात किया जाता है, जो इसके चयनकर्ताओं का वर्णन करता है:
showMessage(gState, text) { return selectors.message.text.replace(gState, text); }.
क्या निकला:

ध्यान दें कि हमारे पास एक प्रेषण था, दो मॉड्यूल में डेटा बदल गया।
यह सब हमें reducers और एक्शन-प्रकार के स्थिरांक से छुटकारा पाने की अनुमति देता है, साथ ही ऊपर उल्लिखित अधिकांश बाधाओं को हल करने या प्राप्त करने के लिए।
इसे और कैसे लागू किया जा सकता है?
यह दृष्टिकोण उपयोग करने के लिए सुविधाजनक है जब यह सुनिश्चित करना आवश्यक है कि आपके नियंत्रण या मॉड्यूल राज्य के विभिन्न टुकड़ों के साथ काम प्रदान करते हैं। मान लीजिए कि हमारे लिए एक कविता पर्याप्त नहीं है। हम चाहते हैं कि उपयोगकर्ता विभिन्न विषयों (बच्चों, रोमांटिक) में दो अलग-अलग टैब पर कविताओं की रचना करने में सक्षम हो। इस मामले में, हम चयनकर्ताओं को तर्क / नियंत्रण में आयात नहीं कर सकते हैं, लेकिन उन्हें बाहरी नियंत्रण में एक पैरामीटर के रूप में निर्दिष्ट करें:
<Poem selectors = {selectors.hildPoem}/> <Poem selectors = {selectors.romanticPoem}/>
और, आगे, इस पैरामीटर को एक्शन क्रेटर्स पास करें। यह पूरी तरह से संलग्न घटकों और तर्क का एक जटिल संयोजन बनाने के लिए पर्याप्त है, जिससे इसका पुन: उपयोग करना आसान हो जाता है।
अपरिवर्तनीय चयनकर्ताओं का उपयोग करते समय सीमाएं:यह "नाम" स्थिति में कुंजी का उपयोग करने के लिए काम नहीं करेगा, क्योंकि मूल फ़ंक्शन के लिए आरक्षित संपत्ति को ओवरराइड करने का प्रयास होगा।
परिणाम क्या है?
परिणामस्वरूप, एक अपेक्षाकृत लचीला दृष्टिकोण प्राप्त किया गया था, विकास की सुविधा को बनाए रखते हुए पाठ स्थिरांक द्वारा अंतर्निहित कोड संबंधों को समाप्त कर दिया गया था, ओवरहेड को कम कर दिया गया था। समय यात्रा की संभावना के साथ एक पूरी तरह से कार्य करने वाला रिडक्स इंस्पेक्टर भी है। मुझे मानक reducers पर लौटने की कोई इच्छा नहीं है।
सामान्य तौर पर, यह सब है। आपके समय के लिए धन्यवाद। शायद किसी को इसे बाहर की कोशिश करने में दिलचस्पी होगी!