एक पुस्तकालय सोच के जाल में न पड़ें कि कैसे सब कुछ करना चाहिए । यदि आप जावास्क्रिप्ट में टाइमआउट के साथ कुछ करना चाहते हैं, तो आपको उपयोग करने की आवश्यकता है setTimeout
। कोई कारण नहीं है कि Redux क्रियाएं किसी भी भिन्न क्यों न हों।
Redux अतुल्यकालिक सामान से निपटने के कुछ वैकल्पिक तरीके प्रदान करता है , लेकिन आपको केवल उनका उपयोग करना चाहिए जब आपको एहसास हो कि आप बहुत अधिक कोड दोहरा रहे हैं। जब तक आपको यह समस्या नहीं होती है, तब तक जो भाषा प्रदान करती है उसका उपयोग करें और सरलतम समाधान के लिए जाएं।
Async कोड इनलाइन लिखना
यह अब तक का सबसे सरल तरीका है। और यहाँ Redux के लिए कुछ खास नहीं है।
store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
इसी तरह, एक जुड़े घटक के अंदर से:
this.props.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
this.props.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
अंतर केवल इतना है कि एक जुड़े घटक में आमतौर पर आपके पास स्टोर तक ही पहुंच नहीं होती है, लेकिन dispatch()
या तो या विशिष्ट एक्शन क्रिएटरों को प्रॉप्स के रूप में इंजेक्ट किया जाता है। हालाँकि इससे हमें कोई फर्क नहीं पड़ता है।
यदि आप विभिन्न घटकों से समान क्रियाओं को भेजते समय टाइपोस बनाना पसंद नहीं करते हैं, तो आप एक्शन ऑब्जेक्ट्स को इनलाइन भेजने के बजाय एक्शन क्रिएटर्स को निकालना चाह सकते हैं:
// actions.js
export function showNotification(text) {
return { type: 'SHOW_NOTIFICATION', text }
}
export function hideNotification() {
return { type: 'HIDE_NOTIFICATION' }
}
// component.js
import { showNotification, hideNotification } from '../actions'
this.props.dispatch(showNotification('You just logged in.'))
setTimeout(() => {
this.props.dispatch(hideNotification())
}, 5000)
या, यदि आपने पहले उन्हें साथ में बांधा है connect()
:
this.props.showNotification('You just logged in.')
setTimeout(() => {
this.props.hideNotification()
}, 5000)
अभी तक हमने किसी मिडलवेयर या अन्य उन्नत अवधारणा का उपयोग नहीं किया है।
Async एक्शन क्रिएटर को निकालना
ऊपर का दृष्टिकोण सरल मामलों में ठीक काम करता है लेकिन आप पा सकते हैं कि इसमें कुछ समस्याएं हैं:
- यह आपको इस तर्क की नकल करने के लिए मजबूर करता है, कहीं भी आप एक अधिसूचना दिखाना चाहते हैं।
- यदि आपके पास दो सूचनाएं तेज़ी से दिखाई देती हैं, तो सूचनाओं की कोई आईडी नहीं है, इसलिए आपके पास दौड़ की स्थिति होगी। जब पहला टाइमआउट खत्म हो जाता है, तो यह
HIDE_NOTIFICATION
टाइमआउट के बाद गलती से दूसरी अधिसूचना को जल्द ही छिपा देगा ।
इन समस्याओं को हल करने के लिए, आपको एक फ़ंक्शन निकालने की आवश्यकता होगी जो टाइमआउट तर्क को केंद्रीकृत करता है और उन दो कार्यों को भेजता है। यह इस तरह लग सकता है:
// actions.js
function showNotification(id, text) {
return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
return { type: 'HIDE_NOTIFICATION', id }
}
let nextNotificationId = 0
export function showNotificationWithTimeout(dispatch, text) {
// Assigning IDs to notifications lets reducer ignore HIDE_NOTIFICATION
// for the notification that is not currently visible.
// Alternatively, we could store the timeout ID and call
// clearTimeout(), but we’d still want to do it in a single place.
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
अब घटक showNotificationWithTimeout
इस तर्क को दोहराए बिना या विभिन्न सूचनाओं के साथ दौड़ की स्थिति होने पर उपयोग कर सकते हैं :
// component.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')
// otherComponent.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged out.')
पहले तर्क के रूप में क्यों showNotificationWithTimeout()
स्वीकार करता dispatch
है? क्योंकि इसे स्टोर में कार्रवाई भेजने की आवश्यकता है। आम तौर पर एक घटक की पहुंच होती है dispatch
लेकिन चूंकि हम डिस्पैचिंग पर नियंत्रण रखना चाहते हैं, इसलिए हमें इसे डिस्पैचिंग पर नियंत्रण देने की आवश्यकता है।
यदि आपके पास कुछ मॉड्यूल से निर्यात किया गया एक सिंगलटन स्टोर था, तो आप इसे dispatch
सीधे आयात कर सकते हैं और इसके बजाय सीधे उस पर:
// store.js
export default createStore(reducer)
// actions.js
import store from './store'
// ...
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
const id = nextNotificationId++
store.dispatch(showNotification(id, text))
setTimeout(() => {
store.dispatch(hideNotification(id))
}, 5000)
}
// component.js
showNotificationWithTimeout('You just logged in.')
// otherComponent.js
showNotificationWithTimeout('You just logged out.')
यह सरल दिखता है, लेकिन हम इस दृष्टिकोण की अनुशंसा नहीं करते हैं । इसका मुख्य कारण हम इसे नापसंद करते हैं क्योंकि यह स्टोर को एक सिंगलटन होने के लिए मजबूर करता है । इससे सर्वर रेंडरिंग को लागू करना बहुत कठिन हो जाता है । सर्वर पर, आप चाहते हैं कि प्रत्येक अनुरोध का अपना स्टोर हो, ताकि विभिन्न उपयोगकर्ताओं को अलग-अलग प्रीलोडेड डेटा मिले।
एक सिंगलटन स्टोर भी परीक्षण को कठिन बनाता है। एक्शन क्रिएटर्स का परीक्षण करते समय आप किसी स्टोर का मजाक नहीं उड़ा सकते क्योंकि वे एक विशिष्ट मॉड्यूल से निर्यात किए गए एक विशिष्ट वास्तविक स्टोर का संदर्भ देते हैं। आप इसके राज्य को बाहर से भी रीसेट नहीं कर सकते।
इसलिए जब आप तकनीकी रूप से एक मॉड्यूल से एक सिंगलटन स्टोर का निर्यात कर सकते हैं, तो हम इसे हतोत्साहित करते हैं। ऐसा तब तक न करें जब तक आपको यकीन न हो कि आपका ऐप कभी सर्वर रेंडरिंग नहीं करेगा।
पिछले संस्करण पर वापस जाना:
// actions.js
// ...
let nextNotificationId = 0
export function showNotificationWithTimeout(dispatch, text) {
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
// component.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')
// otherComponent.js
showNotificationWithTimeout(this.props.dispatch, 'You just logged out.')
यह तर्क के दोहराव के साथ समस्याओं को हल करता है और हमें दौड़ की स्थिति से बचाता है।
थन मिडलवेयर
सरल ऐप के लिए, दृष्टिकोण को पर्याप्त होना चाहिए। यदि आप इससे खुश हैं तो मिडलवेयर की चिंता न करें।
हालाँकि, बड़े ऐप्स में, आपको इसके आस-पास कुछ असुविधाएँ हो सकती हैं।
उदाहरण के लिए, यह दुर्भाग्यपूर्ण है कि हमें dispatch
चारों ओर से गुजरना होगा । इससे कंटेनर और प्रस्तुति घटकों को अलग करना मुश्किल हो जाता है क्योंकि कोई भी घटक जो Redux क्रियाओं को ऊपर के तरीके से अतुल्यकालिक रूप से भेजता dispatch
है, उसे एक प्रस्ताव के रूप में स्वीकार करना पड़ता है ताकि वह इसे और आगे पारित कर सके। आप एक्शन क्रिएटर्स को अभी नहीं बांध connect()
सकते क्योंकि showNotificationWithTimeout()
वास्तव में एक्शन क्रिएटर नहीं है। यह एक Redux कार्रवाई वापस नहीं करता है।
इसके अलावा, यह याद रखना अजीब हो सकता है कि कौन से फ़ंक्शंस सिंक्रोनस एक्शन क्रिएटर हैं जैसे showNotification()
और जो एसिंक्रोनस हेल्पर्स जैसे हैं showNotificationWithTimeout()
। आपको उन्हें अलग तरह से इस्तेमाल करना होगा और सावधान रहना होगा कि वे एक-दूसरे के साथ गलती न करें।
यह सहायक कार्य प्रदान dispatch
करने के इस पैटर्न को "वैध" करने का एक तरीका खोजने के लिए प्रेरणा थी , और Redux को पूरी तरह से विभिन्न कार्यों के बजाय सामान्य क्रिया रचनाकारों के विशेष मामले के रूप में इस तरह के अतुल्यकालिक कार्रवाई रचनाकारों को "देखने" में मदद करता है।
यदि आप अभी भी हमारे साथ हैं और आप भी अपने ऐप में एक समस्या के रूप में पहचानते हैं, तो आप Redux Thunk मिडलवेयर का उपयोग करने के लिए स्वागत करते हैं ।
वास्तव में कार्यों में होने वाली विशेष प्रकार की क्रियाओं को पहचानने के लिए Redux Thunk Redux सिखाता है:
import { createStore, applyMiddleware } from 'redux'
import thunk from 'redux-thunk'
const store = createStore(
reducer,
applyMiddleware(thunk)
)
// It still recognizes plain object actions
store.dispatch({ type: 'INCREMENT' })
// But with thunk middleware, it also recognizes functions
store.dispatch(function (dispatch) {
// ... which themselves may dispatch many times
dispatch({ type: 'INCREMENT' })
dispatch({ type: 'INCREMENT' })
dispatch({ type: 'INCREMENT' })
setTimeout(() => {
// ... even asynchronously!
dispatch({ type: 'DECREMENT' })
}, 1000)
})
जब यह मिडलवेयर सक्षम होता है, यदि आप किसी फंक्शन को भेजते हैं , तो Redux Thunk मिडलवेयर इसे dispatch
एक तर्क के रूप में देगा । यह इस तरह की कार्रवाइयों को "निगल" भी करेगा ताकि अजीब फ़ंक्शन तर्क प्राप्त करने वाले अपने reducers के बारे में चिंता न करें। आपके रिड्यूसर केवल सादे ऑब्जेक्ट एक्शन प्राप्त करेंगे - या तो सीधे उत्सर्जित होते हैं, या फ़ंक्शंस द्वारा उत्सर्जित होते हैं जैसा कि हमने अभी वर्णन किया है।
यह बहुत उपयोगी नहीं दिखता है, यह करता है? इस विशेष स्थिति में नहीं। हालांकि यह हमें showNotificationWithTimeout()
एक नियमित Redux एक्शन निर्माता के रूप में घोषित करता है:
// actions.js
function showNotification(id, text) {
return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
return { type: 'HIDE_NOTIFICATION', id }
}
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
return function (dispatch) {
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
}
ध्यान दें कि फ़ंक्शन हम पिछले अनुभाग में लिखे गए के समान लगभग समान है। हालाँकि यह dispatch
पहले तर्क के रूप में स्वीकार नहीं करता है। इसके बजाय यह एक फ़ंक्शन देता है dispatch
जो पहले तर्क के रूप में स्वीकार करता है।
हम इसे अपने घटक में कैसे उपयोग करेंगे? निश्चित रूप से, हम इसे लिख सकते हैं:
// component.js
showNotificationWithTimeout('You just logged in.')(this.props.dispatch)
हम आंतरिक फ़ंक्शन को प्राप्त करने के लिए async क्रिया निर्माता को कॉल कर रहे हैं जो बस चाहता है dispatch
, और फिर हम पास होते हैं dispatch
।
हालाँकि यह मूल संस्करण की तुलना में अधिक अजीब है! हम भी उस रास्ते पर क्यों गए?
इससे पहले जो मैंने आपको बताया था। यदि Redux Thunk मिडलवेयर सक्षम है, तो किसी भी समय आप किसी एक्शन ऑब्जेक्ट के बजाय फ़ंक्शन को भेजने का प्रयास करते हैं, मिडिलवेयर उस फ़ंक्शन dispatch
को पहले तर्क के रूप में विधि के साथ कॉल करेगा ।
तो हम इसके बजाय यह कर सकते हैं:
// component.js
this.props.dispatch(showNotificationWithTimeout('You just logged in.'))
अंत में, एक अतुल्यकालिक कार्रवाई (वास्तव में, क्रियाओं की एक श्रृंखला) को भेजने से घटक के लिए एक एकल कार्रवाई को भेजने से अलग नहीं दिखता है। यह अच्छा है क्योंकि घटकों को परवाह नहीं करनी चाहिए कि क्या कुछ तुल्यकालिक या अतुल्यकालिक रूप से होता है। हमने अभी-अभी अमूर्त किया है।
ध्यान दें कि जब से हमने "सिखाया" Redux को ऐसे "विशेष" एक्शन क्रिएटर्स को पहचानने के लिए (हम उन्हें थंक एक्शन क्रिएटर कहते हैं ), अब हम उन्हें किसी भी स्थान पर उपयोग कर सकते हैं जहाँ हम नियमित एक्शन क्रिएटर्स का उपयोग करेंगे। उदाहरण के लिए, हम उनका उपयोग कर सकते हैं connect()
:
// actions.js
function showNotification(id, text) {
return { type: 'SHOW_NOTIFICATION', id, text }
}
function hideNotification(id) {
return { type: 'HIDE_NOTIFICATION', id }
}
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
return function (dispatch) {
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
}
// component.js
import { connect } from 'react-redux'
// ...
this.props.showNotificationWithTimeout('You just logged in.')
// ...
export default connect(
mapStateToProps,
{ showNotificationWithTimeout }
)(MyComponent)
थ्रक्स में स्टेट पढ़ना
आमतौर पर आपके रिड्यूसर में अगले राज्य का निर्धारण करने के लिए व्यावसायिक तर्क होते हैं। हालाँकि, क्रियाओं को भेजने के बाद reducers केवल किक करते हैं। क्या होगा यदि आपके पास एक थंक एक्शन क्रिएटर में साइड इफेक्ट (जैसे एपीआई कॉल करना) है, और आप इसे किसी शर्त के तहत रोकना चाहते हैं?
थंक मिडलवेयर का उपयोग किए बिना, आप बस घटक के अंदर यह जांच करेंगे:
// component.js
if (this.props.areNotificationsEnabled) {
showNotificationWithTimeout(this.props.dispatch, 'You just logged in.')
}
हालाँकि, एक्शन क्रिएटर को निकालने का बिंदु कई घटकों में इस दोहराव वाले तर्क को केंद्रीकृत करना था। सौभाग्य से, Redux Thunk आपको Redux स्टोर की वर्तमान स्थिति पढ़ने का एक तरीका प्रदान करता है । इसके अलावा dispatch
, यह getState
उस फ़ंक्शन के दूसरे तर्क के रूप में भी जाता है जिसे आप अपने थंक एक्शन क्रिएटर से वापस करते हैं। यह थंक स्टोर की वर्तमान स्थिति को पढ़ने देता है।
let nextNotificationId = 0
export function showNotificationWithTimeout(text) {
return function (dispatch, getState) {
// Unlike in a regular action creator, we can exit early in a thunk
// Redux doesn’t care about its return value (or lack of it)
if (!getState().areNotificationsEnabled) {
return
}
const id = nextNotificationId++
dispatch(showNotification(id, text))
setTimeout(() => {
dispatch(hideNotification(id))
}, 5000)
}
}
इस पैटर्न का दुरुपयोग न करें। कैश डेटा उपलब्ध होने पर एपीआई कॉल से बाहर निकलना अच्छा है, लेकिन यह आपके व्यापार तर्क को बनाने के लिए बहुत अच्छी नींव नहीं है। यदि आप getState()
केवल अलग-अलग कार्यों को सशर्त रूप से भेजने के लिए उपयोग करते हैं, तो इसके बजाय व्यापार तर्क को रिड्यूसर में डालने पर विचार करें।
अगला कदम
अब आपके पास एक बुनियादी अंतर्ज्ञान है कि थ्रॉक्स कैसे काम करते हैं, Redux async उदाहरण देखें जो उनका उपयोग करता है।
आपको ऐसे कई उदाहरण मिल सकते हैं जिनमें थ्रो वापस आने का वादा करता है। यह आवश्यक नहीं है, लेकिन बहुत सुविधाजनक हो सकता है। Redux को इस बात से कोई फ़र्क नहीं पड़ता है कि आप एक थंक से क्या लौटाते हैं, लेकिन यह आपको इसकी वापसी का मूल्य देता है dispatch()
। यही कारण है कि आप एक थंक से एक वादा वापस कर सकते हैं और कॉल करके इसे पूरा करने की प्रतीक्षा कर सकते हैं dispatch(someThunkReturningPromise()).then(...)
।
आप जटिल थंक एक्शन क्रिएटर्स को कई छोटे थंक एक्शन क्रिएटर्स में विभाजित कर सकते हैं। dispatch
Thunks द्वारा प्रदान की विधि ही Thunks स्वीकार कर सकते हैं, तो आप पैटर्न रिकर्सिवली आवेदन कर सकते हैं। फिर, यह वादा के साथ सबसे अच्छा काम करता है क्योंकि आप उस के शीर्ष पर अतुल्यकालिक नियंत्रण प्रवाह को लागू कर सकते हैं।
कुछ ऐप्स के लिए, आप अपने आप को एक ऐसी स्थिति में पा सकते हैं, जहाँ आपके अतुल्यकालिक नियंत्रण प्रवाह की आवश्यकताएं भी थ्रक्स के साथ व्यक्त की जानी बहुत जटिल हैं। उदाहरण के लिए, असफल अनुरोधों को पुन: प्राप्त करना, टोकन के साथ सौंदर्यीकरण प्रवाह, या इस तरह से लिखे जाने पर एक कदम-दर-चरण ऑनबोर्डिंग बहुत क्रिया और त्रुटि-प्रवण हो सकता है। इस मामले में, आप अधिक उन्नत अतुल्यकालिक नियंत्रण प्रवाह समाधान जैसे Redux Saga या Redux Loop को देखना चाह सकते हैं । उनका मूल्यांकन करें, अपनी आवश्यकताओं के लिए प्रासंगिक उदाहरणों की तुलना करें, और आपको जो सबसे ज्यादा पसंद है उसे चुनें।
अंत में, अगर आप उनके लिए वास्तविक जरूरत नहीं है तो कुछ भी (थ्रॉक्स सहित) का उपयोग न करें। याद रखें कि आवश्यकताओं के आधार पर, आपका समाधान उतना ही सरल लग सकता है
store.dispatch({ type: 'SHOW_NOTIFICATION', text: 'You logged in.' })
setTimeout(() => {
store.dispatch({ type: 'HIDE_NOTIFICATION' })
}, 5000)
जब तक आप यह नहीं जानते कि आप ऐसा क्यों कर रहे हैं, तो इसे न करें।
redux-saga
यदि आप थ्रक्स से बेहतर कुछ चाहते हैं, तो मेरे आधारित उत्तर की जांच करना न भूलें । देर से जवाब तो आप इसे प्रदर्शित करने से पहले एक लंबे समय स्क्रॉल करने के लिए है :) इसका मतलब यह नहीं है कि यह पढ़ने लायक नहीं है। यहाँ एक शॉर्टकट है: stackoverflow.com/a/38574266/82609