javascript برنامج - غير قادر على الوصول إلى مثيل React(هذا)داخل معالج الأحداث




فيلم babel (10)

يمكنك معالجة هذا بثلاث طرق

1.Bind وظيفة الحدث في منشئ نفسه على النحو التالي

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
    this.changeContent = this.changeContent.bind(this);
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

2.Bind عندما يتم استدعاؤها

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent.bind(this)}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

3.By باستخدام وظائف السهم

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={()=>this.sendContent()}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

أنا أكتب مكون بسيط في ES6 (مع BabelJS) ، وظائف هذا. this.setState لا يعمل.

تتضمن الأخطاء النموذجية شيئًا مثل

لا يمكن قراءة الخاصية "setState" غير معرفة

أو

this.setState ليست وظيفة

هل تعرف لماذا؟ هنا هو الرمز:

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

يمكنك حل هذا باتباع هذه الخطوات

قم بتغيير وظيفة sendContent باستخدام

 sendContent(e) {
    console.log('sending input content '+this.refs.someref.value)
  }

تغيير وظيفة التقديم

<input type="text" ref="someref" value={this.state.inputContent} 
          onChange={(event)=>this.changeContent(event)} /> 
   <button onClick={(event)=>this.sendContent(event)}>Submit</button>

هذه المسألة هي واحدة من أول الأشياء التي React.createClass() معظمنا ، عند الانتقال من بناء جملة تعريف مكون React.createClass() إلى طريقة الفئة React.Component لتوسيع React.Component .

ينتج عن this الاختلافات السياق في React.createClass() مقابل extends React.Component .

باستخدام React.createClass() سيقوم تلقائيًا بربط this السياق (القيم) بشكل صحيح ، ولكن ليس هذا هو الحال عند استخدام فئات ES6. عند القيام بذلك بطريقة ES6 (عن طريق توسيع React.Component ) ، يكون this السياق null بشكل افتراضي. لا ترتبط خصائص الفئة تلقائيًا بمثيل الطبقة (المكون) React.

طرق لحل هذه المشكلة

أعرف ما مجموعه 4 طرق عامة.

  1. ربط المهام الخاصة بك في منشئ الفصل . يعتبره الكثيرون منهجًا لأفضل الممارسات يتجنب لمس JSX على الإطلاق ولا ينشئ وظيفة جديدة على كل مكون إعادة عرض.

    class SomeClass extends React.Component {
      constructor(props) {
        super(props);
        this.handleClick = this.handleClick.bind(this);
      }
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick}></button>
        );
      }
    }
    
  2. ربط الوظائف الخاصة بك في السطر . لا يزال بإمكانك العثور على هذا النهج المستخدم هنا وهناك في بعض البرامج التعليمية / المقالات / الخ ، لذا من المهم أن تكون على دراية به. انها نفس المفهوم مثل # 1 ، ولكن يجب أن تدرك أن ربط وظيفة يخلق وظيفة جديدة لكل إعادة تقديم.

    class SomeClass extends React.Component {
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick.bind(this)}></button>
        );
      }
    }
    
  3. استخدم وظيفة السهم الدهون . حتى وظائف السهم ، تحدد كل وظيفة جديدة this القيمة الخاصة بها. ومع ذلك ، لا تقوم وظيفة السهم بإنشاء السياق الخاص بها ، لذلك this له المعنى الأصلي من مثيل مكون React. لذلك ، يمكننا:

    class SomeClass extends React.Component {
      handleClick() {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={ () => this.handleClick() }></button>
        );
      }
    }
    

    أو

    class SomeClass extends React.Component {
      handleClick = () => {
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={this.handleClick}></button>
        );
      }
    }
    
  4. استخدم مكتبة وظيفة الأداة المساعدة لربط وظائفك تلقائيًا . هناك عدد قليل من المكتبات العامة ، التي تقوم بهذه المهمة تلقائيًا نيابة عنك. في ما يلي بعض الشائع ، على سبيل المثال لا الحصر:

    • Autobind Decorator هو عبارة عن حزمة NPM تقوم بربط أساليب الفئة إلى المثيل الصحيح ، حتى عند فصل الطرق. تستخدم الحزمة @autobind قبل الطرق لربط this بالإشارة الصحيحة إلى سياق المكون.

      import autobind from 'autobind-decorator';
      
      class SomeClass extends React.Component {
        @autobind
        handleClick() {
          console.log(this); // the React Component instance
        }
        render() {
          return (
            <button onClick={this.handleClick}></button>
          );
        }
      }
      

      يتميز Autobind Decorator بالذكاء الكافي للسماح لنا بربط جميع الطرق داخل فئة مكون في وقت واحد ، تمامًا مثل الطريقة رقم 1.

    • Class Autobind هي حزمة NPM أخرى تستخدم على نطاق واسع لحل هذه المشكلة الملزمة. على عكس Autobind Decorator ، فإنه لا يستخدم نمط الزخرفة ، ولكنه يستخدم وظيفة داخل المُنشئ الذي يربط أساليب المكوّن تلقائيًا بالمرجع الصحيح this .

      import autobind from 'class-autobind';
      
      class SomeClass extends React.Component {
        constructor() {
          autobind(this);
          // or if you want to bind only only select functions:
          // autobind(this, 'handleClick');
        }
        handleClick() {
          console.log(this); // the React Component instance
        }
        render() {
          return (
            <button onClick={this.handleClick}></button>
          );
        }
      }
      

      ملاحظة: مكتبة أخرى مشابهة جدا هو رد الفعل Autobind .

توصية

إذا كنت أنت ، كنت سألتزم بالمقاربة رقم 1. ومع ذلك ، بمجرد أن تحصل على الكثير من الروابط في مُنشئ الفصل ، أوصيك باستكشاف إحدى المكتبات المساعدة المذكورة في المقاربة رقم 4.

آخر

لا يتعلق الأمر بالمشكلة التي تواجهها ، ولكن لا يجب الإفراط في استخدام الحكام .

قد يتمثل الميل الأول في استخدام الحكام في "تحقيق أشياء" في تطبيقك. إذا كان هذا هو الحال ، فكر في لحظة وفكر بشكل أكثر نقديًا حول المكان الذي يجب أن تكون فيه الدولة مملوكة في التسلسل الهرمي للمكوّنات.

لأغراض مماثلة ، تمامًا مثل ما تحتاج إليه ، فإن استخدام مكون يتم التحكم فيه هو الطريقة المفضلة. أقترح عليك النظر في استخدام state المكون الخاص بك. لذلك ، يمكنك ببساطة الوصول إلى القيمة مثل: this.state.inputContent .


توصيتي هي استخدام وظائف السهم كخاصية

class SomeClass extends React.Component {
  handleClick = () => {
    console.log(this); // the React Component instance
  }
  render() {
    return (
      <button onClick={this.handleClick}></button>
    );
  }
}

ولا تستخدم وظائف السهم

class SomeClass extends React.Component {
      handleClick(){
        console.log(this); // the React Component instance
      }
      render() {
        return (
          <button onClick={()=>{this.handleClick}}></button>
        );
      }
    }

لأن النهج الثاني سيولد وظيفة جديدة كل استدعاء يجعل في الواقع هذا يعني إصدار جديد جديد من الدعائم ، مما لو كنت تهتم فيما بعد بالأداء يمكنك استخدام React.PureComponent أو في React.Component يمكنك تجاوز shouldComponentUpdate (nextProps، nextState) وفحص الضحلة عندما وصلت الدعائم


مرحبا إذا كنت لا تهتم حول ملزمة نفسك المكالمة وظيفتك. يمكنك استخدام "class-autobind" واستيرادها من هذا القبيل

import autobind from 'class-autobind';

class test extends Component {
  constructor(props){
  super(props);
  autobind(this);
}

لا تكتب autobind قبل المكالمة الفائقة لأنها لن تنجح


في حال كنت تريد الاحتفاظ بالربط في بنية البناء ، يمكنك استخدام proposal-bind-operator وتحويل شفرتك على النحو التالي:

constructor() {
  this.changeContent = ::this.changeContent;
}

بدلا من :

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

أبسط من ذلك بكثير ، لا حاجة bind(this) أو fatArrow .


نحتاج إلى ربط وظيفة الحدث بالمكون في المُنشئ كما يلي ،

import React from 'react'

class SomeClass extends React.Component {
  constructor(props) {
    super(props)
    this.state = {inputContent: 'startValue'}
    this.changeContent = this.changeContent.bind(this);
  }

  sendContent(e) {
    console.log('sending input content '+React.findDOMNode(React.refs.someref).value)
  }

  changeContent(e) {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return (
      <div>
        <h4>The input form is here:</h4>
        Title: 
        <input type="text" ref="someref" value={this.inputContent} 
          onChange={this.changeContent} /> 
        <button onClick={this.sendContent}>Submit</button>
      </div>
    )
  }
}

export default SomeClass

شكر


يحتاج هذا this.changeContent إلى الالتزام بمثيل المكون عبر this.changeContent.bind(this) قبل تمريره كـ prop onChange ، وإلا لن يشير this المتغير في نص الدالة إلى مثيل المكون ولكن إلى window . انظر Function::bind .

عند استخدام React.createClass بدلاً من فئات ES6 ، تكون كل طريقة غير دورة الحياة المعرفة في أحد المكونات مرتبطة تلقائيًا بمثيل المكون. انظر Autobinding .

يجب أن تدرك أن ربط وظيفة بإنشاء دالة جديدة. يمكنك إما ربطه مباشرة في العرض ، مما يعني أنه سيتم إنشاء وظيفة جديدة في كل مرة يتم عرض المكون أو ربطه في منشئك ، والذي سيطلق مرة واحدة فقط.

constructor() {
  this.changeContent = this.changeContent.bind(this);
}

ضد

render() {
  return <input onChange={this.changeContent.bind(this)} />;
}

يتم تعيين المراجع على مثيل المكون وليس على React.refs : تحتاج إلى تغيير React.refs.someref إلى this.refs.someref . ستحتاج أيضًا إلى ربط أسلوب sendContent بمثيل المكون بحيث يشير إلى ذلك.


موراهاوس صحيح ، لكن هذا يمكن حلها بدون bind .

يمكنك استخدام وظيفة السهم مع اقتراح خصائص الفئة :

class SomeClass extends React.Component {
  changeContent = (e) => {
    this.setState({inputContent: e.target.value})
  } 

  render() {
    return <input type="text" onChange={this.changeContent} />;
  }
}

نظرًا لأنه يتم الإعلان عن دالة السهم في نطاق المُنشئ ، ولأن وظائف السهم تحافظ على this من نطاق التصريح الخاص به ، فكل شيء يعمل. الجانب السلبي هنا هو أن هذه لن تكون وظائف على النموذج ، سيتم إعادة صياغتها مع كل مكون. ومع ذلك ، هذا ليس الكثير من الجانب السلبي منذ bind النتائج في نفس الشيء.


يتم تشغيل حدث change فقط عند تعديل أحد نماذج المجموعات. عند إضافة نموذج إلى المجموعة يتم تشغيل الحدث add .
انظر مجموعة وثائق Backbone.js ':

يمكنك ربط أحداث "التغيير" ليتم إعلامك عند تعديل أي طراز في المجموعة ، والاستماع إلى "إضافة" و "إزالة" الأحداث [...]

للاستماع إلى عند حدوث add تعديل التعليمات البرمجية الخاصة بك

var c = new AwesomeCollection();
c.bind("add", function(){
  console.log('Collection has changed.');
});

c.add({testModel: "Test"}); 




javascript reactjs ecmascript-6 babeljs