事件处理:基于功能的组件与基于类的组件
Posted
技术标签:
【中文标题】事件处理:基于功能的组件与基于类的组件【英文标题】:Event handling: functional based component vs class based component 【发布时间】:2019-07-10 16:49:41 【问题描述】:这是我的第一个 React 应用程序(react@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;
vs 基于类的方法。
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;
【问题讨论】:
this
在函数组件和类组件中的工作方式不同,因此函数的行为也不同。检查 babel 是如何编译它们的
this
在函数组件中并不像在类组件中那样引用组件实例。请改用onClick=onAnswer
。
而不是onClick=this.onAnswer
使用onClick=onAnswer
谢谢大家的解释!
@ElenaJdanova 对答案的支持会有所帮助
【参考方案1】:
MDN web doc 涵盖了您需要了解的有关 this
的所有信息。
为简单起见,请考虑objects
,其中this
是“未定义”,除非:
bind(this)
绑定到 object
(请参阅下面的注释),或者通过使用 object
本身重新绑定外部函数来在 object
之外反弹:bind(obj)
。李>
注意:如下所示(在方法 6 中),在 object
内部使用 ES5 arrow functions
意味着它将保留封闭的词法范围 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>
【讨论】:
【参考方案2】:对于函数式组件,您声明一个常量,其中包含一个函数。如果单击按钮,您要调用它。但请确保在函数中使用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>
);
;
【讨论】:
以上是关于事件处理:基于功能的组件与基于类的组件的主要内容,如果未能解决你的问题,请参考以下文章
Android学习笔记(36):Android的两种事件处理方式
Java AWT 图形界面编程事件处理机制 ③ ( AWT 中常见的事件和事件监听器 | 低级事件 | 组件事件 | 窗口事件 | 鼠标事件 | 高级事件 | 动作事件 | 事件监听器 )
基于类的组件和 inChange 事件中的 function 关键字