जेएसएक्स प्रॉप्स को एरो फ़ंक्शंस या बाइंड का उपयोग क्यों नहीं करना चाहिए?


103

मैं अपने रिएक्ट एप्लिकेशन के साथ एक प्रकार का वृक्ष चला रहा हूं, और मुझे यह त्रुटि मिली है:

error    JSX props should not use arrow functions        react/jsx-no-bind

और यह वह जगह है जहां मैं तीर फ़ंक्शन (अंदर onClick) चला रहा हूं :

{this.state.photos.map(tile => (
  <span key={tile.img}>
    <Checkbox
      defaultChecked={tile.checked}
      onCheck={() => this.selectPicture(tile)}
      style={{position: 'absolute', zIndex: 99, padding: 5, backgroundColor: 'rgba(255, 255, 255, 0.72)'}}
    />
    <GridTile
      title={tile.title}
      subtitle={<span>by <b>{tile.author}</b></span>}
      actionIcon={<IconButton onClick={() => this.handleDelete(tile)}><Delete color="white"/></IconButton>}
    >
      <img onClick={() => this.handleOpen(tile.img)} src={tile.img} style={{cursor: 'pointer'}}/>
    </GridTile>
  </span>
))}

क्या यह एक बुरा अभ्यास है जिसे टाला जाना चाहिए? और इसे करने का सबसे अच्छा तरीका क्या है?

जवाबों:


170

क्यों आप JSX सहारा में इनलाइन तीर कार्यों का उपयोग नहीं करना चाहिए

जेएसएक्स में एरो फ़ंक्शंस या बाइंडिंग का उपयोग करना एक खराब अभ्यास है जो प्रदर्शन को नुकसान पहुंचाता है, क्योंकि प्रत्येक रेंडर पर फ़ंक्शन को फिर से बनाया जाता है।

  1. जब भी कोई फ़ंक्शन बनाया जाता है, तो पिछला फ़ंक्शन कचरा एकत्र किया जाता है। कई तत्वों को प्रस्तुत करने से एनिमेशन में जान पैदा हो सकती है।

  2. इनलाइन एरो फंक्शन का उपयोग करने से PureComponentएस, और घटकों का उपयोग होता shallowCompareहै जो shouldComponentUpdateकिसी भी तरह रेंडर करने की विधि में उपयोग करते हैं । चूंकि हर बार एरो फंक्शन प्रॉप को फिर से बनाया जाता है, इसलिए उथला तुलना इसे प्रॉप में बदलाव के रूप में पहचानेगी, और घटक रेंडर करेगा।

जैसा कि आप निम्न 2 उदाहरणों में देख सकते हैं - जब हम इनलाइन एरो फंक्शन का उपयोग करते हैं, तो <Button>घटक को हर बार रेंडर किया जाता है (कंसोल 'रेंडर बटन' टेक्स्ट दिखाता है)।

उदाहरण 1 - इनलाइन हैंडलर के बिना PureComponent

उदाहरण 2 - इनलाइन हैंडलर के साथ PureComponent

thisबिना तीर के कार्यों को बांधने के तरीके

  1. कंस्ट्रक्टर में मैन्युअल तरीके से बाइंडिंग:

    class Button extends React.Component {
      constructor(props, context) {
        super(props, context);
    
        this.cb = this.cb.bind(this);
      }
    
      cb() {
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }
  2. एक तीर फ़ंक्शन के साथ प्रस्ताव-वर्ग-फ़ील्ड का उपयोग करके एक विधि बांधना । जैसा कि यह एक चरण 3 का प्रस्ताव है, आपको स्टेज 3 प्रीसेट या क्लास प्रॉपर्टीज़ को अपने बैबल कॉन्फ़िगरेशन में बदलना होगा।

    class Button extends React.Component {
      cb = () => { // the class property is initialized with an arrow function that binds this to the class
    
      }
    
      render() {
        return (
          <button onClick={ this.cb }>Click</button>
        );
      }
    }

आंतरिक कॉलबैक के साथ फ़ंक्शन घटक

जब हम किसी फंक्शन कंपोनेंट के अंदर एक इनर फंक्शन (उदाहरण के लिए ईवेंट हैंडलर) बनाते हैं, तो हर बार कंपोनेंट के रेंडर होने पर फंक्शन रीक्रिएट किया जाएगा। यदि फ़ंक्शन एक बच्चे घटक ( Buttonइस मामले में ) के लिए सहारा (या संदर्भ के माध्यम से) के रूप में पारित किया जाता है , तो वह बच्चा फिर से भी प्रस्तुत करेगा।

उदाहरण 1 - आंतरिक कॉलबैक के साथ फ़ंक्शन घटक:

इस समस्या को हल करने के लिए, हम कॉलबैक को useCallback()हुक के साथ लपेट सकते हैं , और निर्भरता को एक खाली सरणी पर सेट कर सकते हैं।

नोट:useState उत्पन्न समारोह एक अपडेटर समारोह, कि वर्तमान स्थिति प्रदान करता है स्वीकार करता है। इस तरह, हमें वर्तमान स्थिति पर निर्भरता निर्धारित करने की आवश्यकता नहीं है useCallback

उदाहरण 2 - उपयोग के साथ लिपटे एक आंतरिक कॉलबैक के साथ फंक्शन घटक:


3
आप इसे स्टेटलेस घटकों पर कैसे प्राप्त करेंगे?
लक्स

4
स्टेटलेस (फ़ंक्शन) घटक नहीं है this, इसलिए बाँधने के लिए कुछ भी नहीं है। आमतौर पर विधियों को एक आवरण स्मार्ट घटक द्वारा आपूर्ति की जाती है।
ओरी ड्रोरी

39
@OriDrori: जब आप कॉलबैक में डेटा पास करना चाहते हैं तो वह कैसे काम करता है? onClick={() => { onTodoClick(todo.id) }
adam-beck

4
@ adam-beck - इसे क्लास में कॉलबैक विधि की परिभाषा में जोड़ें cb() { onTodoClick(this.props.todo.id); }
ओरी ड्रोरी

2
@ adam-beck मुझे लगता है कि यह कैसे useCallbackगतिशील मूल्य के साथ उपयोग करने के लिए है । stackoverflow.com/questions/55006061/…
शोता तमुरा

9

इसका कारण यह है कि एक एरो फंक्शन जाहिरा तौर पर जेएसएक्स प्रॉपर्टी में उपयोग किए जाने पर प्रत्येक रेंडर पर फ़ंक्शन का एक नया उदाहरण बनाएगा। यह कचरा संग्रहकर्ता पर भारी दबाव पैदा कर सकता है और ब्राउज़र को किसी भी "गर्म रास्तों" का अनुकूलन करने से भी रोक देगा क्योंकि पुन: उपयोग के बजाय कार्यों को फेंक दिया जाएगा।

आप पूरी व्याख्या और कुछ और जानकारी https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-no-bind.md पर देख सकते हैं


इतना ही नहीं। हर बार नए फ़ंक्शन इंस्टेंसेस बनाने का मतलब है कि राज्य को संशोधित किया गया है और जब एक घटक के राज्य को संशोधित किया जाता है तो इसे फिर से प्रदान किया जाएगा। चूंकि रिएक्ट का उपयोग करने के मुख्य कारणों में से एक केवल उन तत्वों को प्रस्तुत करना है जो परिवर्तन करते हैं, bindयहां या तीर फ़ंक्शन का उपयोग करके अपने आप को पैर में गोली मार रहे हैं। यह है नहीं अच्छी तरह से है, हालांकि दस्तावेज विशेष रूप से साथ काम करने के मामले में mapसूचियाँ भीतर पिंग सरणियों, आदि
hippietrail

"हर बार नए फ़ंक्शन इंस्टेंसेस बनाने का मतलब है कि राज्य को संशोधित किया गया है" आप इसका क्या मतलब है? इस सवाल पर सभी में कोई राज्य नहीं है
एपी 4of18

4

समान तर्कों के साथ नए फ़ंक्शन बनाने से बचने के लिए, आप फ़ंक्शन बाइंड परिणाम को याद कर सकते हैं, यहां एक सरल उपयोगिता है जिसे memobindइसे करने के लिए नाम दिया गया है: https://github.com/supnate/memobind


4

इस तरह इनलाइन कार्यों का उपयोग करना पूरी तरह से ठीक है। लाइनिंग नियम पुराना है।

यह नियम ऐसे समय से है, जब तीर फ़ंक्शन सामान्य नहीं थे और लोग उपयोग करते थे। बिंद (यह), जो धीमा हुआ करता था। Chrome 49 में प्रदर्शन समस्या को ठीक कर दिया गया है।

ध्यान दें कि आप इनलाइन फ़ंक्शंस को एक बच्चे के घटक के लिए सहारा के रूप में पारित नहीं करते हैं।

रिएक्टर राउटर के लेखक रयान फ्लोरेंस ने इस बारे में एक बेहतरीन बात लिखी है:

https://cdb.reacttraining.com/react-inline-functions-and-performance-bdff784f5578


क्या आप इनलाइन एरो फ़ंक्शंस वाले घटकों पर एक यूनिट टेस्ट लिखने का तरीका बता सकते हैं?
krankuba

1
@ क्रैंकुबा यह वह नहीं है जिसके बारे में यह सवाल था। आप अभी भी उन अनाम फ़ंक्शंस में पास हो सकते हैं जो इनलाइन में परिभाषित नहीं हैं, लेकिन अभी भी परीक्षण योग्य नहीं हैं।
सेबचेलर

-1

आप प्रतिक्रिया-कैश्ड-हैंडलर लाइब्रेरी का उपयोग करके तीर फ़ंक्शंस का उपयोग कर सकते हैं , पुन: रेंडरिंग प्रदर्शन के बारे में चिंतित होने की आवश्यकता नहीं है:

नोट: आंतरिक रूप से यह निर्दिष्ट कुंजी द्वारा आपके तीर कार्यों को कैश करता है, फिर से रेंडरिंग के बारे में चिंतित होने की कोई आवश्यकता नहीं है!

render() {

  return <div>
  {
        this.props.photos.map(photo=>
          <Photo key={photo.url}
            onClick={this.handler(photo.url, (url) => { 
                 console.log(url) })}
          />)
   }
 </div>

}

अन्य सुविधाओं:

  • जिसका नाम हैंडलर्स रखा गया
  • तीर कार्यों द्वारा घटनाओं को संभालना
  • कुंजी, कस्टम तर्क और मूल घटना तक पहुंच
  • घटक प्रतिपादन प्रदर्शन
  • हैंडलर के लिए कस्टम संदर्भ

सवाल यह था कि हम इसका उपयोग क्यों नहीं कर सकते। किसी और हैक के साथ इसका उपयोग कैसे करें।
कपिल

-1

जेएसएक्स प्रॉप्स को एरो फ़ंक्शंस या बाइंड का उपयोग क्यों नहीं करना चाहिए?

अधिकतर, क्योंकि इनलाइन फ़ंक्शन अनुकूलित घटकों के संस्मरण को तोड़ सकते हैं:

परंपरागत रूप से, रिएक्ट में इनलाइन फ़ंक्शन के आसपास प्रदर्शन संबंधी चिंताओं का संबंध इस बात से रहा है कि कैसे प्रत्येक रेंडर पर नए कॉलबैक पास करने shouldComponentUpdateसे बच्चे के घटकों में अनुकूलन हो जाता है । ( डॉक्स )

यह अतिरिक्त समारोह निर्माण लागत के बारे में कम है:

प्रदर्शन के मुद्दे Function.prototype.bind यहां तय हो गए हैं और एरो फ़ंक्शंस या तो एक देशी चीज़ हैं या बबल द्वारा सादे कार्यों में ट्रांसप्लेंड किए जाते हैं; दोनों मामलों में हम मान सकते हैं कि यह धीमा नहीं है। ( प्रतिक्रिया प्रशिक्षण )

मेरा मानना ​​है कि फंक्शन क्रिएशन का दावा करने वाले लोग हमेशा गलत जानकारी देते हैं (रिएक्ट टीम ने कभी यह नहीं कहा)। ( ट्वीट )

कब है react/jsx-no-bindनियम उपयोगी है?

आप यह सुनिश्चित करना चाहते हैं, कि मेमोइज्ड घटक काम करें:

  • React.memo (फ़ंक्शन घटकों के लिए)
  • PureComponentया कस्टम shouldComponentUpdate(वर्ग घटकों के लिए)

इस नियम का पालन करने से, स्थिर फ़ंक्शन ऑब्जेक्ट संदर्भ पास होते हैं। इसलिए उपरोक्त घटक पुन: रेंडरर्स को रोककर प्रदर्शन को अनुकूलित कर सकते हैं, जब पिछले प्रॉप्स नहीं बदले हैं।

ESLint त्रुटि कैसे हल करें?

कक्षाएं: बाध्यकारी के लिए विधि, या वर्ग की संपत्ति के रूप में हैंडलर को परिभाषित करें this
हुक: उपयोग करेंuseCallback

मैदान का मध्य

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

rules: {
  "react/jsx-no-bind": [ "error", { ignoreDOMComponents: true } ],
}

const Comp = () => <span onClick={() => console.log("Hello!")} />; // no warning
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.