Обработка событий: функциональный компонент против классового компонента - PullRequest
0 голосов
/ 17 февраля 2019

Это мое самое первое приложение React (response@16.8.1).Я пытаюсь выяснить, почему событие onClick обрабатывается по-разному при использовании функционального компонента против компонента на основе класса.

Как я знаю, я должен использовать класс на основе c.только когда мне нужно изменить в нем состояние, я прав?

Функциональный компонент выдает _this is undefined error, а класс - нет.

Я использую функции стрелки вместо функции связыванияв обоих случаях.

Функциональный базис:

import React from 'react';

const AnswersDisplay = (props) => {
// even with bind I still get "_this is undefined"
//this.onAnswer = this.onAnswer.bind(this); 

  const answerList = props.answerList.map( (option) => {
    return (
      <button
        onClick={this.onAnswer}
        value={option}
        className="ui basic green button">{option}
      </button>
    )
  }); 

  const onAnswer = (e) =>{
    console.log(e.target.value);
  }

  return(
    <div className="ui two buttons hSpace">{this.answerList}</div>
  );
};

export default AnswersDisplay;

в зависимости от класса, который работает.

import React from 'react';

class AnswersDisplay extends React.Component {
  constructor(props) {
    super(props);
    //this.onAnswer = this.onAnswer.bind(this);
  }

  answerList = this.props.answerList.map( (option) => {
    return (
      <button
        onClick={this.onAnswer}
        value={option}
        className="ui basic green button">{option}
      </button>
    )
  });

  onAnswer = (e) =>{
    console.log(e.target.value);
  }

  render() {
    return(
        <div className="ui two buttons hSpace">{this.answerList}</div>
    );
  }
};


export default AnswersDisplay;

Ответы [ 2 ]

0 голосов
/ 17 февраля 2019

* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

* * * * * * * * * * * *) * * * * * * * * * * *1004* * * * *равно "undefined", если:
  • Метод / функция были привязаны к object с ES5 bind(this) (см. примечание ниже) ИЛИ отскок за пределы object путем повторного связывания внешней функции сobject сам по себе: bind(obj).

Примечание : Как показано ниже (в методе 6), есть исключение при использовании ES5 arrow functions внутри objectозначает, что он сохранит вмещающую лексическую область this без необходимости быть связанным.

Например:

this.prop = "global prop"
const outsideArrowFunction = () => (this.prop)

function outsideFunction() {
    return this.prop;
};

const obj = {
  prop: "obj's prop",
  method: function() {
    return this.prop; // returns "obj's prop"
  },
  method2: function() {
    return this; // returns the entire "obj" and its properties
  },
  method3: function() {
    return this.method(); // returns "obj's prop"
  },
  method4: function() {
    return outsideFunction(); // returns "global prop" because the outsideFunction's lexical scope doesn't recognize the "obj"'s nor its properties      
  },
  method5: function() {
    return outsideArrowFunction(); // same as method4, utilizes global this
  },
  method6: function() {
    const x = () => this.method();
    return x(); // returns "obj's prop" because arrow functions take on "this" from the "obj"
  },
  method7: function() {
    const x = function() { 
       return this.prop; 
    };
    return x(); // returns "global prop" because "this" loses lexical scope upon execution
  },
  method8: function() {
   const x = this.method.bind(this);
   return x(); // returns "obj's prop" because "this" refers to the "obj" upon execution
  },
  method9: function(callback) {
    return callback(this.method);
  },
  method10: function() {
    return this.method9(function(callback) {
      return callback(); // returns "global prop" because "this" loses lexical scope upon execution
    });
  }
}; 


const a = outsideArrowFunction.bind(obj); // returns "global prop" because arrow functions take on whatever "this" is upon its creation, so "this" refers to the global "this"
const b = outsideFunction.bind(obj); // returns "obj's prop" since a traditional function can rebind "this", which has been rebound to "obj"   
    
console.log(`Method: ${obj.method()}`);
console.log(`Method2: ${obj.method2()}`);
console.log(`Method3: ${obj.method3()}`);
console.log(`Method4: ${obj.method4()}`);
console.log(`Method5: ${obj.method5()}`);
console.log(`Method6: ${obj.method6()}`);
console.log(`Method7: ${obj.method7()}`);
console.log(`Method8: ${obj.method8()}`);
console.log(`Method10: ${obj.method10()}`);
console.log(`arrowFunction: ${a()}`);
console.log(`outsideFunction: ${b()}`);

Когда дело доходит до classes, это шаблон objects.Таким образом, this будет undefined или глобальным this, если класс method не связан в constructor или вы не используете arrow function.Попробуйте приведенный ниже пример, нажав на каждую из кнопок, обратите внимание на то, как все 3 метода могут работать, но зависит от того, как они назывались :

class Example extends React.Component {
  constructor() {
    super();
    this.state = { method: "" };
    this.boundMethod = this.boundMethod.bind(this);
  }

  componentDidMount() { 
    this.unboundMethod(); 
  };

  boundMethod() {
    this.setState({ method: "Bound Method" }); // this works because the method is bound to the class
  }

  unboundMethod() {
    try {
      this.setState({ method: "Unbound Method" }); // this only works if it's called within a bound method class (like componentDidMount)
    } catch (err) {
      alert(err); // however, if it's called within a callback (like in an onClick event), it fails.
    }
  }

  arrowMethod = () => {
    this.setState({ method: "Arrow Method" }); // this works because arrow methods are automatically bound to the class
  };

  render() {
    return (
      <div>
        <button onClick={this.boundMethod}>Bound Method</button>
        <button onClick={this.unboundMethod}>Unbound Method</button>
        <button onClick={this.arrowMethod}>Arrow Method</button>
        <p>The {this.state.method} was called</p>
     </div>
    );
  };
}

ReactDOM.render(<Example />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
0 голосов
/ 17 февраля 2019

В случае функциональных компонентов вы объявляете константу, удерживая внутри нее функцию.Который вы хотите позвонить в случае нажатия на кнопку.Но убедитесь, что использование this в функции.this будет ссылаться на глобальный контекст выполнения в этом случае, и в этом конкретном контексте движок JavaScript не сможет найти свойство onAnswer, поэтому он вернет undefined.

Просто чтобы сделать эторабота у вас перезвоните без this.

Примерно так: onClick={onAnswer}

В целом код будет выглядеть следующим образом:

import React from 'react';

const AnswersDisplay = (props) => {
// even with bind I still get "_this is undefined"
//this.onAnswer = this.onAnswer.bind(this); 

  const answerList = props.answerList.map( (option) => {
    return (
      <button
        onClick={onAnswer}
        value={option}
        className="ui basic green button">{option}
      </button>
    )
  }); 

  const onAnswer = (e) =>{
    console.log(e.target.value);
  }

  return(
    <div className="ui two buttons hSpace">{this.answerList}</div>
  );
};
...