मैं react
कोड का एक गुच्छा पढ़ रहा हूं और मुझे इस तरह से सामान दिखाई देता है जो मुझे समझ में नहीं आता है:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
मैं react
कोड का एक गुच्छा पढ़ रहा हूं और मुझे इस तरह से सामान दिखाई देता है जो मुझे समझ में नहीं आता है:
handleChange = field => e => {
e.preventDefault();
/// Do something here
}
जवाबों:
यह एक क्यूरेटेड फंक्शन है
सबसे पहले, दो मापदंडों के साथ इस फ़ंक्शन की जाँच करें ...
const add = (x, y) => x + y
add(2, 3) //=> 5
यहाँ यह फिर से विचित्र रूप में है ...
const add = x => y => x + y
यहाँ एक ही है 1 तीर कार्यों के बिना कोड ...
const add = function (x) {
return function (y) {
return x + y
}
}
ध्यान केंद्रित करना return
यह इसे दूसरे तरीके से देखने में मदद कर सकता है। हम जानते हैं कि एरो फ़ंक्शंस इस तरह काम करते हैं - चलो वापसी मूल्य पर विशेष ध्यान दें ।
const f = someParam => returnValue
इसलिए हमारे add
समारोह एक रिटर्न समारोह - हम जोड़ा स्पष्टता के लिए कोष्ठक का उपयोग कर सकते हैं। बोल्ड पाठ हमारे समारोह के रिटर्न मान हैadd
const add = x => (y => x + y)
add
कुछ संख्या के दूसरे शब्दों में एक फ़ंक्शन देता है
add(2) // returns (y => 2 + y)
कॉल किए गए कार्य
तो हमारे करी समारोह का उपयोग करने के लिए, हमें इसे थोड़ा अलग तरीके से कॉल करना होगा ...
add(2)(3) // returns 5
ऐसा इसलिए है क्योंकि पहला (बाहरी) फ़ंक्शन कॉल एक दूसरा (आंतरिक) फ़ंक्शन देता है। दूसरे फ़ंक्शन को कॉल करने के बाद ही हमें वास्तव में परिणाम मिलता है। यह अधिक स्पष्ट है अगर हम कॉल को दो लाइनों पर अलग करते हैं ...
const add2 = add(2) // returns function(y) { return 2 + y }
add2(3) // returns 5
हमारी नई समझ को अपने कोड में लागू करना
संबंधित: "बाध्यकारी, आंशिक अनुप्रयोग और करी के बीच अंतर क्या है?"
ठीक है, अब हम समझते हैं कि यह कैसे काम करता है, आइए अपने कोड को देखें
handleChange = field => e => {
e.preventDefault()
/// Do something here
}
हम तीर कार्यों का उपयोग किए बिना इसका प्रतिनिधित्व करके शुरू करेंगे ...
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
};
};
हालाँकि, क्योंकि तीर लेक्सिक रूप से काम करता है this
, यह वास्तव में इस तरह दिखेगा ...
handleChange = function(field) {
return function(e) {
e.preventDefault()
// Do something here
// return ...
}.bind(this)
}.bind(this)
शायद अब हम देख सकते हैं कि यह अधिक स्पष्ट रूप से क्या कर रहा है। handleChange
समारोह एक निर्दिष्ट के लिए एक समारोह पैदा कर रही है field
। यह एक आसान रिएक्ट तकनीक है क्योंकि आपको अपने एप्लिकेशन को अपडेट करने के लिए प्रत्येक इनपुट पर अपने श्रोताओं को सेटअप करने की आवश्यकता होती है। handleChange
फ़ंक्शन का उपयोग करके , हम सभी डुप्लिकेट किए गए कोड को समाप्त कर सकते हैं, जिसके परिणामस्वरूप change
प्रत्येक क्षेत्र के लिए श्रोता स्थापित किए जाएंगे । ठंडा!
1 यहाँ मुझे this
मूल रूप से बाँधने की ज़रूरत नहीं थी क्योंकि मूल add
फ़ंक्शन किसी संदर्भ का उपयोग नहीं करता है, इसलिए इस मामले में इसे संरक्षित करना महत्वपूर्ण नहीं है।
और भी तीर
यदि आवश्यक हो तो दो से अधिक तीर फ़ंक्शंस का अनुक्रम किया जा सकता है -
const three = a => b => c =>
a + b + c
const four = a => b => c => d =>
a + b + c + d
three (1) (2) (3) // 6
four (1) (2) (3) (4) // 10
करीने वाले कार्य आश्चर्यजनक चीजों में सक्षम हैं। नीचे हम $
दो मापदंडों के साथ एक क्युरेटेड फ़ंक्शन के रूप में परिभाषित देखते हैं , फिर भी कॉल साइट पर, ऐसा प्रतीत होता है जैसे हम किसी भी तर्क की आपूर्ति कर सकते हैं। Currying की अमूर्त है arity -
const $ = x => k =>
$ (k (x))
const add = x => y =>
x + y
const mult = x => y =>
x * y
$ (1) // 1
(add (2)) // + 2 = 3
(mult (6)) // * 6 = 18
(console.log) // 18
$ (7) // 7
(add (1)) // + 1 = 8
(mult (8)) // * 8 = 64
(mult (2)) // * 2 = 128
(mult (2)) // * 2 = 256
(console.log) // 256
आंशिक आवेदन
आंशिक अनुप्रयोग एक संबंधित अवधारणा है। यह हमें कार्य को आंशिक रूप से लागू करने की अनुमति देता है, करी के समान, सिवाय फ़ंक्शन को करी रूप में परिभाषित किए जाने की आवश्यकता नहीं है -
const partial = (f, ...a) => (...b) =>
f (...a, ...b)
const add3 = (x, y, z) =>
x + y + z
partial (add3) (1, 2, 3) // 6
partial (add3, 1) (2, 3) // 6
partial (add3, 1, 2) (3) // 6
partial (add3, 1, 2, 3) () // 6
partial (add3, 1, 1, 1, 1) (1, 1, 1, 1, 1) // 3
यहाँ partial
आप अपने ब्राउज़र में साथ काम कर सकते हैं -
const partial = (f, ...a) => (...b) =>
f (...a, ...b)
const preventDefault = (f, event) =>
( event .preventDefault ()
, f (event)
)
const logKeypress = event =>
console .log (event.which)
document
.querySelector ('input[name=foo]')
.addEventListener ('keydown', partial (preventDefault, logKeypress))
<input name="foo" placeholder="type here to see ascii codes" size="50">
$
का उपयोग अवधारणा को प्रदर्शित करने के लिए किया गया था, लेकिन आप इसे जो चाहें नाम दे सकते हैं। संयोगवश, लेकिन पूरी तरह से असंबंधित, $
का उपयोग लोकप्रिय पुस्तकालयों में किया गया है जैसे कि jQuery, जहां $
कार्यों के पूरे पुस्तकालय में वैश्विक प्रवेश बिंदु की तरह है। मुझे लगता है कि यह दूसरों में भी इस्तेमाल किया गया है। एक और आप देखेंगे _
कि अंडरस्कोर और लॉश जैसे पुस्तकालयों में लोकप्रिय है। कोई भी प्रतीक दूसरे से अधिक सार्थक नहीं है; आप अपने कार्यक्रम के लिए अर्थ प्रदान करते हैं । यह केवल मान्य जावास्क्रिप्ट है: D
$
इसका बेहतर उपयोग करके देख सकते हैं कि इसका उपयोग कैसे किया जाता है। यदि आप स्वयं कार्यान्वयन के बारे में पूछ रहे हैं, $
तो एक फ़ंक्शन है जो एक मान प्राप्त करता है x
और एक नया फ़ंक्शन देता है k => ...
। लौटे फ़ंक्शन के शरीर को देखते हुए, हम देखते हैं k (x)
कि हम जानते हैं कि k
यह भी एक फ़ंक्शन होना चाहिए, और जो भी परिणाम होता k (x)
है उसे वापस डाल दिया जाता है $ (...)
, जिसे हम जानते हैं कि एक k => ...
और रिटर्न होता है , और इस पर जाता है ... यदि आप अभी भी हैं अटक जाना, मुझे बता देना।
abc(1,2,3)
आदर्श से कम है abc(1)(2)(3)
। कोड के तर्क के बारे में तर्क करना कठिन है और फ़ंक्शन एबीसी को पढ़ना मुश्किल है और फ़ंक्शन कॉल को पढ़ना मुश्किल है। इससे पहले कि आप केवल यह जानना चाहते हैं कि एबीसी क्या करता है, अब आप सुनिश्चित नहीं हैं कि एबीसी नामांकित कार्य क्या कर रहा है, और उस पर दो बार।
तीर फ़ंक्शन के उपलब्ध सिंटैक्स को समझना समझने से आपको इस बात की समझ मिल जाएगी कि उपलब्ध कराए गए उदाहरणों में 'जंजीर' की तरह वे किस व्यवहार का परिचय दे रहे हैं।
जब एक तीर फ़ंक्शन को कई मापदंडों के साथ या उसके बिना ब्लॉक ब्रेसिज़ के लिखा जाता है, तो फ़ंक्शन के शरीर का गठन करने वाला अभिव्यक्ति निहित रूप से वापस आ जाता है। आपके उदाहरण में, वह अभिव्यक्ति एक और एरो फंक्शन है।
No arrow funcs Implicitly return `e=>{…}` Explicitly return `e=>{…}`
---------------------------------------------------------------------------------
function (field) { | field => e => { | field => {
return function (e) { | | return e => {
e.preventDefault() | e.preventDefault() | e.preventDefault()
} | | }
} | } | }
तीर सिंटैक्स का उपयोग करके अनाम फ़ंक्शंस लिखने का एक और लाभ यह है कि वे उस दायरे के लिए बाध्य हैं जिसमें वे परिभाषित हैं। से MDN पर 'तीर कार्यों' :
एक तीर समारोह अभिव्यक्ति की तुलना में एक छोटे वाक्य रचना है समारोह भाव और lexically बांधता है इस मूल्य। एरो फ़ंक्शंस हमेशा गुमनाम होते हैं ।
यह आपके उदाहरण में विशेष रूप से उचित है, यह देखते हुए कि यह एक से लिया गया है reactjsआवेदन। जैसा कि @naomik द्वारा बताया गया है, प्रतिक्रिया में आप अक्सर एक घटक के सदस्य कार्यों का उपयोग करते हैं this
। उदाहरण के लिए:
Unbound Explicitly bound Implicitly bound
------------------------------------------------------------------------------
function (field) { | function (field) { | field => e => {
return function (e) { | return function (e) { |
this.setState(...) | this.setState(...) | this.setState(...)
} | }.bind(this) |
} | }.bind(this) | }
एक सामान्य टिप, यदि आप किसी नए जेएस सिंटैक्स से भ्रमित हो जाते हैं और यह कैसे संकलित करेगा, तो आप बेबल की जांच कर सकते हैं । उदाहरण के लिए अपने कोड को बेबिल में कॉपी करना और es2015 प्रीसेट का चयन करना इस तरह से आउटपुट देगा
handleChange = function handleChange(field) {
return function (e) {
e.preventDefault();
// Do something here
};
};
इसे इस तरह समझें, हर बार जब आप एक तीर देखते हैं, तो आप इसे बदल देते हैं function
। function parameters
तीर से पहले परिभाषित कर रहे हैं।
तो आपके उदाहरण में:
field => // function(field){}
e => { e.preventDefault(); } // function(e){e.preventDefault();}
और फिर एक साथ:
function (field) {
return function (e) {
e.preventDefault();
};
}
डॉक्स से :
// Basic syntax:
(param1, param2, paramN) => { statements }
(param1, param2, paramN) => expression
// equivalent to: => { return expression; }
// Parentheses are optional when there's only one argument:
singleParam => { statements }
singleParam => expression
this
।
संक्षिप्त और सरल 🎈
यह एक ऐसा फंक्शन है जो शॉर्ट में लिखे गए दूसरे फंक्शन को वापस करता है।
const handleChange = field => e => {
e.preventDefault()
// Do something here
}
// is equal to
function handleChange(field) {
return function(e) {
e.preventDefault()
// Do something here
}
}
लोग ऐसा क्यों करते हैं ❓
क्या आपको सामना करना पड़ा है जब आपको एक फ़ंक्शन लिखने की आवश्यकता होती है जिसे अनुकूलित किया जा सकता है? या आपको एक कॉलबैक फ़ंक्शन लिखना होगा जिसमें निश्चित पैरामीटर (तर्क) हैं, लेकिन आपको फ़ंक्शन को अधिक चर पास करने की आवश्यकता है लेकिन वैश्विक चर से बचना चाहिए? अगर आपका जवाब “ हाँ " है तो यह तरीका है कि इसे कैसे किया जाए।
उदाहरण के लिए हमारे पास button
onClick कॉलबैक है। और हमें id
फ़ंक्शन को पास करने की आवश्यकता है , लेकिन onClick
केवल एक पैरामीटर को स्वीकार करता है event
, हम इस तरह से अतिरिक्त पैरामीटर पारित नहीं कर सकते हैं:
const handleClick = (event, id) {
event.preventDefault()
// Dispatch some delete action by passing record id
}
यह काम नहीं करेगा!
इसलिए हम एक फ़ंक्शन बनाते हैं जो अन्य फ़ंक्शन को बिना किसी वैश्विक चर के अपने स्वयं के दायरे के साथ लौटाएगा, क्योंकि वैश्विक चर बुराई which हैं।
फ़ंक्शन के handleClick(props.id)}
नीचे बुलाया जाएगा और एक फ़ंक्शन लौटाएगा और id
इसके दायरे में होगा ! कोई फर्क नहीं पड़ता कि कितनी बार इसे दबाया जाएगा आईडी प्रभाव या एक दूसरे को नहीं बदलेंगे, वे पूरी तरह से पृथक हैं।
const handleClick = id => event {
event.preventDefault()
// Dispatch some delete action by passing record id
}
const Confirm = props => (
<div>
<h1>Are you sure to delete?</h1>
<button onClick={handleClick(props.id)}>
Delete
</button>
</div
)
आपके प्रश्न में उदाहरण एक का है curried function
जो उपयोग करता है arrow function
और एक हैimplicit return
पहले तर्क के लिए है।
एरो फंक्शन को शाब्दिक रूप से बाँधते हैं यानी उनके पास अपना this
तर्क नहीं होता है, लेकिन this
एनक्लोज़िंग स्कोप से वैल्यू लेते हैं
उपरोक्त कोड के बराबर होगा
const handleChange = (field) {
return function(e) {
e.preventDefault();
/// Do something here
}.bind(this);
}.bind(this);
अपने उदाहरण के बारे में ध्यान देने वाली एक और बात यह है कि handleChange
एक कास्ट या फ़ंक्शन के रूप में परिभाषित किया गया है। संभवतः आप इसे एक वर्ग विधि के हिस्से के रूप में उपयोग कर रहे हैं और यह एक का उपयोग करता हैclass fields syntax
इसलिए बाहरी कार्य को सीधे बाँधने के बजाय, आप इसे क्लास कंस्ट्रक्टर में बाँध देंगे
class Something{
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange(field) {
return function(e) {
e.preventDefault();
// do something
}
}
}
उदाहरण में एक और बात ध्यान देने योग्य और स्पष्ट रिटर्न के बीच का अंतर है।
const abc = (field) => field * 2;
ऊपर निहित प्रतिफल का उदाहरण है। यह मान फ़ील्ड को तर्क के रूप में लेता है और परिणाम देता हैfield*2
जो स्पष्ट रूप से फ़ंक्शन को लौटने के लिए निर्दिष्ट करता है
स्पष्ट वापसी के लिए आप मूल्य वापस करने की विधि स्पष्ट रूप से बताएंगे
const abc = () => { return field*2; }
तीर के कार्यों के बारे में ध्यान देने योग्य एक और बात यह है कि उनके पास अपना स्वयं का नहीं है, arguments
बल्कि विरासत में है कि माता-पिता के दायरे से भी।
उदाहरण के लिए यदि आप एक तीर फ़ंक्शन को परिभाषित करते हैं जैसे
const handleChange = () => {
console.log(arguments) // would give an error on running since arguments in undefined
}
वैकल्पिक तीर फ़ंक्शन के रूप में आप उपयोग कर सकते हैं कि बाकी मापदंडों प्रदान करते हैं
const handleChange = (...args) => {
console.log(args);
}
यह पूरी तरह से संबंधित नहीं हो सकता है, लेकिन चूंकि प्रश्न उल्लिखित प्रतिक्रिया का उपयोग करता है (और मैं इस SO थ्रेड में टकराता रहता हूं): डबल एरो फ़ंक्शन का एक महत्वपूर्ण पहलू है जिसका स्पष्ट रूप से यहां उल्लेख नहीं किया गया है। केवल 'पहला' एरो (फंक्शन) नाम दिया जाता है (और रन-टाइम द्वारा 'डिफरेंशियल'), कोई भी निम्न एरो गुमनाम होता है और हर रेंडर पर 'नए' ऑब्जेक्ट के रूप में रिएक्ट पॉइंट से व्यू काउंट होता है।
इस प्रकार डबल एरो फंक्शन किसी भी PureComponent को हर समय रेंडर करने का कारण बनेगा।
उदाहरण
आपके पास एक परिवर्तनशील हैंडलर के साथ एक मूल घटक है:
handleChange = task => event => { ... operations which uses both task and event... };
और जैसे एक रेंडर के साथ:
{
tasks.map(task => <MyTask handleChange={this.handleChange(task)}/>
}
handleChange तो एक इनपुट या क्लिक पर इस्तेमाल किया। और यह सब काम करता है और बहुत अच्छा लगता है। लेकिन इसका मतलब यह है कि किसी भी परिवर्तन से माता-पिता को रेंडर करने वाला (जैसे कि पूरी तरह से असंबंधित राज्य परिवर्तन) हो जाएगा, यह आपके सभी MyTask के साथ-साथ PureCompords होते हुए भी फिर से प्रस्तुत करेगा।
इसे कई तरीकों से समाप्त किया जा सकता है जैसे कि 'सबसे बाहरी' तीर को पार करना और आप जिस वस्तु के साथ उसे खाना खिलाएंगे या एक कस्टम शोअपडेट लिखेंगे या मूल नाम पर वापस जा सकते हैं जैसे कि फ़ंक्शन नाम लिखना (और इसे मैन्युअल रूप से बांधना ...)