तुम नहीं।
लेकिन ... आपको redux-saga का उपयोग करना चाहिए :)
डैन अब्रामोव का जवाब सही है, redux-thunk
लेकिन मैं Redux-saga के बारे में थोड़ा और बात करूंगा जो काफी समान है लेकिन अधिक शक्तिशाली है।
इंपीरियल वीएस घोषणात्मक
- DOM : jQuery जरूरी है / प्रतिक्रियाशील घोषणात्मक है
- मोनाड्स : IO अत्यावश्यक है / मुक्त घोषणात्मक है
- Redux प्रभाव :
redux-thunk
अनिवार्य / redux-saga
घोषणात्मक है
जब आपके हाथों में एक कांटा होता है, जैसे कि IO मोनाद या एक वादा, आप आसानी से नहीं जान सकते कि यह एक बार निष्पादित होने पर क्या करेगा। एक ठग का परीक्षण करने का एकमात्र तरीका इसे निष्पादित करना है, और डिस्पैचर (या अगर यह पूरी सामग्री के साथ इंटरैक्ट करता है ...) तो मॉक डिस्पैचर का मजाक उड़ाएं।
यदि आप मोज़ेक का उपयोग कर रहे हैं, तो आप कार्यात्मक प्रोग्रामिंग नहीं कर रहे हैं।
साइड-इफेक्ट्स के लेंस के माध्यम से देखा गया, मॉक एक ध्वज है जो आपका कोड अशुद्ध है, और कार्यात्मक प्रोग्रामर की नज़र में, सबूत है कि कुछ गलत है। हिमशैल की जाँच करने में हमारी मदद करने के लिए एक पुस्तकालय डाउनलोड करने के बजाय बरकरार है, हमें इसके चारों ओर नौकायन करना चाहिए। एक कट्टर टीडीडी / जावा आदमी ने एक बार मुझसे पूछा था कि तुम क्लोजर में कैसे मॉकिंग करते हो। जवाब है, हम आमतौर पर नहीं है। हम आम तौर पर इसे एक संकेत के रूप में देखते हैं हमें अपने कोड को फिर से भरने की आवश्यकता है।
स्रोत
सगाओं (जैसा कि उन्हें लागू किया गया redux-saga
) घोषणात्मक हैं और फ्री मोनाड या रिएक्ट घटकों की तरह, वे बिना किसी नकली के परीक्षण के लिए बहुत आसान हैं।
इस लेख को भी देखें :
आधुनिक एफपी में, हमें कार्यक्रम नहीं लिखना चाहिए - हमें कार्यक्रमों का वर्णन लिखना चाहिए, जिसे हम तब इच्छा-शक्ति में बदल सकते हैं, व्याख्या कर सकते हैं और व्याख्या कर सकते हैं।
(वास्तव में, Redux-saga एक हाइब्रिड की तरह है: प्रवाह अत्यावश्यक है लेकिन प्रभाव घोषणात्मक हैं)
भ्रम: क्रियाएँ / घटनाएँ / आदेश ...
फ्रंटएंड की दुनिया में बहुत भ्रम है कि CQRS / EventSourcing और Flux / Redux जैसी कुछ बैकएंड अवधारणाएं कैसे संबंधित हो सकती हैं, ज्यादातर इसलिए क्योंकि फ्लक्स में हम "एक्शन" शब्द का उपयोग करते हैं जो कभी-कभी अनिवार्य कोड ( LOAD_USER
) और घटनाओं दोनों का प्रतिनिधित्व कर सकता है। USER_LOADED
)। मेरा मानना है कि ईवेंट-सोर्सिंग की तरह, आपको केवल ईवेंट भेजना चाहिए।
व्यवहार में सगाओं का उपयोग करना
उपयोगकर्ता प्रोफ़ाइल के लिंक के साथ एक ऐप की कल्पना करें। प्रत्येक मिडलवेयर के साथ इसे संभालने का मुहावरेदार तरीका होगा:
redux-thunk
<div onClick={e => dispatch(actions.loadUserProfile(123)}>Robert</div>
function loadUserProfile(userId) {
return dispatch => fetch(`http://data.com/${userId}`)
.then(res => res.json())
.then(
data => dispatch({ type: 'USER_PROFILE_LOADED', data }),
err => dispatch({ type: 'USER_PROFILE_LOAD_FAILED', err })
);
}
redux-saga
<div onClick={e => dispatch({ type: 'USER_NAME_CLICKED', payload: 123 })}>Robert</div>
function* loadUserProfileOnNameClick() {
yield* takeLatest("USER_NAME_CLICKED", fetchUser);
}
function* fetchUser(action) {
try {
const userProfile = yield fetch(`http://data.com/${action.payload.userId }`)
yield put({ type: 'USER_PROFILE_LOADED', userProfile })
}
catch(err) {
yield put({ type: 'USER_PROFILE_LOAD_FAILED', err })
}
}
इस गाथा का अनुवाद है:
जब भी कोई उपयोगकर्ता नाम क्लिक करता है, तो उपयोगकर्ता प्रोफ़ाइल प्राप्त करता है और फिर भरी हुई प्रोफ़ाइल के साथ एक घटना भेजता है।
जैसा कि आप देख सकते हैं, के कुछ फायदे हैं redux-saga
।
यह takeLatest
व्यक्त करने के लिए परमिट का उपयोग कि आप केवल अंतिम उपयोगकर्ता नाम के डेटा को प्राप्त करने में रुचि रखते हैं (उपयोगकर्ता के बहुत उपयोगकर्ता नाम पर बहुत तेज़ी से क्लिक करने पर समसामयिक समस्याओं को हैंडल करें)। इस तरह का सामान थ्रक्स के साथ कठिन है। takeEvery
यदि आप इस व्यवहार को नहीं चाहते हैं तो आप इसका इस्तेमाल कर सकते हैं ।
आप एक्शन क्रिएटर्स को शुद्ध रखते हैं। ध्यान दें कि एक्शनक्रिएटर्स (सागों put
और घटकों में dispatch
) रखना अभी भी उपयोगी है , क्योंकि यह आपको भविष्य में एक्शन वैलिडेशन (दावे / प्रवाह / टाइपस्क्रिप्ट) जोड़ने में मदद कर सकता है।
आपका कोड बहुत अधिक परीक्षण योग्य हो जाता है क्योंकि प्रभाव घोषणात्मक होते हैं
आपको अब जैसे आरपीसी जैसी कॉल को ट्रिगर करने की आवश्यकता नहीं है actions.loadUser()
। आपके यूआई को केवल यह बताने की जरूरत है कि क्या है। हम केवल आग की घटनाओं (हमेशा पिछले तनाव में!) और अब कार्रवाई नहीं करते हैं। इसका मतलब है कि आप डिकोड किए गए "बतख" या बाउंडेड कॉन्टेक्ट्स बना सकते हैं और यह कि गाथा इन मॉड्यूलर घटकों के बीच युग्मन बिंदु के रूप में कार्य कर सकती है।
इसका मतलब है कि आपके विचार प्रबंधित करना अधिक आसान है क्योंकि उन्हें उस अनुवाद परत को शामिल करने की आवश्यकता नहीं है जो कि घटित हुई है और एक प्रभाव के रूप में क्या होना चाहिए
उदाहरण के लिए एक अनंत स्क्रॉल दृश्य की कल्पना करें। CONTAINER_SCROLLED
के लिए नेतृत्व कर सकते हैं NEXT_PAGE_LOADED
, लेकिन क्या यह सच है कि स्क्रॉल करने योग्य कंटेनर की जिम्मेदारी यह तय करने के लिए है कि हमें एक और पेज लोड करना चाहिए या नहीं? फिर उसे अधिक जटिल सामानों के बारे में पता होना चाहिए जैसे कि पिछले पृष्ठ को सफलतापूर्वक लोड किया गया था या नहीं या यदि पहले से ही कोई पृष्ठ है जो लोड करने की कोशिश करता है, या यदि लोड करने के लिए और अधिक आइटम नहीं बचा है? मुझे ऐसा नहीं लगता: अधिकतम पुन: प्रयोज्य के लिए स्क्रॉल करने योग्य कंटेनर को केवल यह वर्णन करना चाहिए कि इसे स्क्रॉल किया गया है। किसी पृष्ठ का लोडिंग उस स्क्रॉल का "व्यावसायिक प्रभाव" है
कुछ लोग तर्क दे सकते हैं कि जनरेटर स्थानीय चर के साथ स्वाभाविक रूप से रिडक्स स्टोर के बाहर राज्य को छिपा सकते हैं, लेकिन यदि आप टाइमर आदि शुरू करके थनों के अंदर जटिल चीजों को ऑर्केस्ट्रेट करना शुरू करते हैं तो आपको वैसे भी समस्या होगी। और इसका एक select
प्रभाव है जो अब आपके Redux स्टोर से कुछ राज्य प्राप्त करने की अनुमति देता है।
सगा समय-यात्रा की जा सकती है और जटिल प्रवाह लॉगिंग और देव-उपकरण को सक्षम बनाती है जो वर्तमान में काम कर रहे हैं। यहाँ कुछ सरल async प्रवाह लॉगिंग है जो पहले से ही लागू है:
decoupling
सगा न केवल रेडक्स थ्रक्स की जगह ले रहे हैं। वे बैकएंड / वितरित सिस्टम / इवेंट-सोर्सिंग से आते हैं।
यह एक बहुत ही आम गलत धारणा है कि सागा सिर्फ यहाँ हैं ताकि आपके रेडक्स थ्रक्स को बेहतर परीक्षण के साथ बदल दिया जा सके। वास्तव में यह रेडक्स-गाथा का एक कार्यान्वयन विवरण है। डिसेबल प्रभाव के लिए थ्रक्स की तुलना में डिक्लेक्टिव इफेक्ट्स का उपयोग करना बेहतर है, लेकिन अनिवार्य या डिक्लेक्टिव कोड के आधार पर गाथा पैटर्न को लागू किया जा सकता है।
पहली जगह में, गाथा सॉफ्टवेयर का एक टुकड़ा है जो लंबे समय तक चलने वाले लेनदेन (अंततः स्थिरता) और विभिन्न बंधे हुए संदर्भों (डोमेन संचालित डिजाइन शब्दजाल) में लेनदेन को समन्वित करने की अनुमति देता है।
फ्रंटएंड वर्ल्ड के लिए इसे सरल बनाने के लिए, विजेट 1 और विजेट 2 की कल्पना करें। जब विजेट 1 के कुछ बटन पर क्लिक किया जाता है, तो विजेट 2 पर इसका प्रभाव होना चाहिए। 2 विगेट्स को एक साथ युग्मित करने के बजाय (यानी विजेट 1 विजेट 2 को लक्षित करने वाली क्रिया को प्रेषित करता है), विजेट 1 केवल प्रेषण करता है कि इसके बटन पर क्लिक किया गया था। तब गाथा इस बटन पर क्लिक करने के लिए सुनती है और फिर विजेट 2 से अवगत होने वाली एक नई घटना का प्रसारण करके विजेट 2 को अपडेट करती है।
यह एक अप्रत्यक्ष स्तर जोड़ता है जो सरल ऐप्स के लिए अनावश्यक है, लेकिन जटिल अनुप्रयोगों को स्केल करना अधिक आसान बनाता है। अब आप विजेट 1 और विजेट 2 को अलग-अलग एनपीएम रिपॉजिटरी में प्रकाशित कर सकते हैं, ताकि उन्हें एक-दूसरे के बारे में कभी भी पता न चले, इसके लिए उन्हें कार्रवाई की वैश्विक रजिस्ट्री साझा करने की आवश्यकता नहीं है। 2 विजेट अब बंधे हुए संदर्भ हैं जो अलग-अलग रह सकते हैं। उन्हें एक दूसरे के अनुरूप होने की आवश्यकता नहीं है और अन्य ऐप में भी इसका पुन: उपयोग किया जा सकता है। गाथा दो विगेट्स के बीच युग्मन बिंदु है जो उन्हें आपके व्यवसाय के लिए सार्थक तरीके से समन्वयित करता है।
अपने Redux ऐप को कैसे तैयार करें, इस पर कुछ अच्छे लेख, जिन पर आप डिकॉक्सिंग कारणों से Redux-saga का उपयोग कर सकते हैं:
एक ठोस usecase: अधिसूचना प्रणाली
मैं चाहता हूं कि मेरे घटक इन-ऐप सूचनाओं के प्रदर्शन को ट्रिगर करने में सक्षम हों। लेकिन मैं नहीं चाहता कि मेरे घटकों को अधिसूचना प्रणाली के लिए अत्यधिक युग्मित किया जाए जिसके अपने स्वयं के व्यावसायिक नियम हैं (अधिकतम 3 सूचनाएं एक ही समय में प्रदर्शित की जाती हैं, अधिसूचना कतारबद्ध, 4 सेकंड डिस्प्ले-टाइम आदि ...)।
मैं नहीं चाहता कि मेरे JSX घटक यह तय करें कि अधिसूचना कब दिखाई जाएगी / छिप जाएगी। मैं इसे केवल एक अधिसूचना का अनुरोध करने की क्षमता देता हूं, और गाथा के अंदर के जटिल नियमों को छोड़ देता हूं। इस तरह का सामान थ्रेड्स या वादों के साथ लागू करने के लिए काफी कठिन है।
मैंने यहाँ वर्णन किया है कि यह गाथा के साथ कैसे किया जा सकता है
इसे सागा क्यों कहा जाता है?
गाथा शब्द बैकेंड की दुनिया से आता है। मैंने शुरू में एक लंबी चर्चा में यासीन (Redux-saga के लेखक) को उस शब्द से परिचित कराया ।
प्रारंभ में, उस शब्द को एक पेपर के साथ पेश किया गया था , गाथा पैटर्न को वितरित लेनदेन में अंततः स्थिरता को संभालने के लिए इस्तेमाल किया जाना था, लेकिन इसका उपयोग बैकएंड डेवलपर्स द्वारा एक व्यापक परिभाषा तक बढ़ा दिया गया है ताकि यह अब "प्रक्रिया प्रबंधक" को भी कवर करे। पैटर्न (किसी तरह मूल गाथा पैटर्न प्रक्रिया प्रबंधक का एक विशेष रूप है)।
आज, "गाथा" शब्द भ्रामक है क्योंकि यह 2 अलग-अलग चीजों का वर्णन कर सकता है। जैसा कि इसका उपयोग redux-saga में किया जाता है, यह वितरित लेनदेन को संभालने का तरीका नहीं बताता है, बल्कि आपके ऐप में कार्यों को समन्वित करने का एक तरीका है। redux-saga
भी बुलाया जा सकता था redux-process-manager
।
यह सभी देखें:
वैकल्पिक
यदि आपको जनरेटर का उपयोग करने का विचार पसंद नहीं है, लेकिन आप गाथा पैटर्न और इसके डिकॉउलिंग गुणों से रूचि रखते हैं, तो आप इसे redux-observable के साथ भी प्राप्त कर सकते हैं जो epic
सटीक उसी पैटर्न का वर्णन करने के लिए नाम का उपयोग करता है , लेकिन RxJS के साथ। यदि आप पहले से ही Rx से परिचित हैं, तो आप घर पर सही महसूस करेंगे।
const loadUserProfileOnNameClickEpic = action$ =>
action$.ofType('USER_NAME_CLICKED')
.switchMap(action =>
Observable.ajax(`http://data.com/${action.payload.userId}`)
.map(userProfile => ({
type: 'USER_PROFILE_LOADED',
userProfile
}))
.catch(err => Observable.of({
type: 'USER_PROFILE_LOAD_FAILED',
err
}))
);
कुछ redux-saga उपयोगी संसाधन
2017 की सलाह है
- Redux-saga को केवल उपयोग करने के लिए अधिक उपयोग न करें। परीक्षण योग्य एपीआई कॉल केवल इसके लायक नहीं है।
- सबसे सरल मामलों के लिए अपने प्रोजेक्ट से थ्रक्स न निकालें।
yield put(someActionThunk)
अगर यह समझ में आता है , तो फेंकता को फैलाने में संकोच न करें ।
यदि आप Redux-saga (या Redux-observable) का उपयोग करने से डरते हैं, लेकिन बस decoupling पैटर्न की आवश्यकता है, तो redux-dispatch-subscribe की जांच करें : यह श्रोता में नए प्रेषण भेजने और ट्रिगर करने के लिए सुनने की अनुमति देता है।
const unsubscribe = store.addDispatchListener(action => {
if (action.type === 'ping') {
store.dispatch({ type: 'pong' });
}
});