我在ES6中编写了一个简单的组件(使用BabelJS),函数 this.setState
无效 .
典型错误包括类似的内容
无法读取undefined的属性'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
16 回答
this.changeContent
需要在作为onChange
prop传递之前通过this.changeContent.bind(this)
绑定到组件实例,否则函数体中的this
变量将不会引用组件实例而是引用window
. 见Function::bind .使用
React.createClass
而不是ES6类时,组件上定义的每个非生命周期方法都会自动绑定到组件实例 . 见Autobinding .请注意,绑定函数会创建一个新函数 . 您可以直接在render中绑定它,这意味着每次组件渲染时都会创建一个新函数,或者在构造函数中绑定它,它只会触发一次 .
VS
Refs在组件实例上设置而不在
React.refs
上:您需要将React.refs.someref
更改为this.refs.someref
. 您还需要将sendContent
方法绑定到组件实例,以便this
引用它 .Morhaus是正确的,但这可以在没有
bind
的情况下解决 .您可以将arrow function与class properties proposal一起使用:
因为箭头函数是在构造函数的范围内声明的,并且因为箭头函数从它们的声明范围维护
this
,所以它都可以工作 . 这里的缺点是这些不是原型上的函数,它们都将用每个组件重新创建 . 然而,这并不是一个缺点,因为bind
导致同样的事情 .当从
React.createClass()
组件定义语法转换到扩展React.Component
的ES6类方式时,这个问题是我们大多数人经历的第一件事 .It is caused by the this context differences in React.createClass() vs extends React.Component .
使用
React.createClass()
将自动正确绑定this
context(值),但使用ES6类时则不然 . 在执行ES6方式时(通过扩展React.Component
),this
上下文默认为null
. 该类的属性不会自动绑定到React类(组件)实例 .解决此问题的方法
我知道共有4种一般方法 .
this
值 . 但是,箭头函数不会创建自己的this
上下文,因此this
具有React组件实例的原始含义 . 因此,我们可以:要么
Use utility function library to automatically bind your functions . 有一些实用程序库可以自动完成这项工作 . 以下是一些流行的,仅举几例:
Autobind Decorator是一个NPM包,它将类的方法绑定到正确的
this
实例,即使这些方法是分离的 . 包 uses @autobind before methods to bind this to the correct reference 到组件的上下文 .Autobind Decorator很聪明,可以让我们一次绑定组件类中的所有方法,就像方法#1一样 .
this
.PS:其他非常相似的库是React Autobind .
建议
如果我是你,我会坚持使用方法#1 . 但是,一旦你在类构造函数中获得大量绑定,我建议你去探索方法#4中提到的一个帮助库 .
其他
这与你遇到的问题无关,但是你shouldn't overuse refs .
出于类似的目的,就像你需要的那样,使用controlled component是首选方式 . 我建议你考虑使用你的Component state . 因此,您可以像这样访问值:
this.state.inputContent
.我们需要将事件函数与构造函数中的组件绑定,如下所示,
谢谢
发生此问题是因为
this.changeContent
和onClick={this.sendContent}
未绑定到组件实例的 this .还有另一个解决方案(除了在构造函数()中使用bind())使用ES6的箭头函数,它们共享周围代码的相同词法范围并维护 this ,因此您可以将render()中的代码更改为:
您好,如果您不想关心绑定自己的函数调用 . 你可以使用'class-autobind'并像那样导入它
不要在超级调用之前编写autobind,因为它不起作用
如果你想在构造函数语法中保持绑定,你可以使用proposal-bind-operator并转换你的代码,如下所示:
代替 :
更简单,不需要
bind(this)
或fatArrow
.你可以通过三种方式解决这个问题
1.在构造函数本身中绑定事件函数,如下所示
2.绑定时绑定
3.使用箭头功能
我的建议是使用箭头功能作为属性
并且不要使用箭头功能
因为第二种方法会在每次渲染调用时生成新函数实际上这意味着新指针新版本的道具,如果你以后关心性能你可以使用 React.PureComponent 或者 React.Component 你可以覆盖 shouldComponentUpdate(nextProps, nextState) 并在道具到达时进行浅层检查
这个问题发生在react15.0之后,哪个事件处理程序没有自动绑定到组件 . 因此,只要调用事件处理程序,就必须手动将其绑定到组件 .
有几种方法可以解决这个问题 . 但你需要知道哪种方法最好,为什么?通常,我们建议在类构造函数中绑定函数或使用箭头函数 .
每次组件渲染时,这两个方法都不会创建新函数 . 所以我们的ChildComponent不会因为新功能道具的改变而受到影响,或者可能会产生性能问题 .
您可以按照以下步骤解决此问题
使用更改sendContent函数
用改变渲染功能
虽然之前的答案已经提供了解决方案的基本概述(即绑定,箭头功能,为你做这个的装饰器),但我还没有找到一个答案,这实际上解释了 why 这是必要的 - 在我看来这是根混乱,并导致不必要的步骤,如不必要的重新绑定和盲目跟随别人的行为 .
这是动态的
要了解这种具体情况,请简要介绍
this
的工作原理 . 这里的关键是this
是一个运行时绑定,它取决于当前的执行上下文 . 因此,为什么它通常被称为当前执行上下文的"context" -giving信息,以及为什么需要绑定是因为你松散"context" . 但是,让我用一个片段来说明问题:在这个例子中,我们按预期得到
3
. 但举个例子:发现它记录未定义可能是意外的 -
3
去了哪里?答案在"context",或者你如何执行一个函数 . 比较我们如何调用这些函数:注意区别 . 在第一个示例中,我们在
foobar
对象上准确指定了bar
method1所在的位置:但是在第二个中,我们将方法存储到一个新变量中,并使用该变量来调用该方法,而无需明确说明该方法实际存在的位置, thus losing context :
其中存在的问题是,当您在变量中存储方法时,有关该方法所在位置的原始信息(执行该方法的上下文)将丢失 . 没有这些信息,在运行时,JavaScript解释器无法绑定正确的
this
- 没有特定的上下文,this
无法按预期工作2 .与React有关
以下是一个由于
this
问题导致的React组件(简称为简洁)的示例:但是为什么,以前的部分与此有何关系?这是因为他们遭受同样问题的抽象 . 如果你看一下React handles event handlers:
因此,当您执行
onClick={this.handleClick}
时,方法this.handleClick
最终会分配给变量listener
3.但现在您看到问题出现了 - 因为我们已将this.handleClick
分配给listener
,我们不再确切地指定handleClick
的来源!从React的角度来看,listener
只是一些函数,没有附加到任何对象(或者在这种情况下,React组件实例) . 我们丢失了上下文,因此解释器无法推断this
值以使用 insidehandleClick
.为什么绑定有效
您可能想知道,如果解释器在运行时决定
this
值,为什么我可以绑定处理程序以使其正常工作?这是因为您可以使用Function#bind
来保证运行时的this
值 . 这是通过在函数上设置内部this
绑定属性来完成的,允许它不推断this
:执行此行时,可能在构造函数中,捕获当前的
this
(React组件实例)并设置为内部this
绑定一个全新的函数,从Function#bind
返回 . 这可以确保在运行时计算this
时,解释器不会尝试推断任何内容,而是使用您提供的this
值 .为什么箭头功能属性有效
箭头函数类属性目前通过基于转换的Babel工作:
变为:
这是因为箭头函数确实绑定了它们自己的这个,但是取其封闭范围的
this
. 在这种情况下,constructor
的this
,指向React组件实例 - 从而为您提供正确的this
.41我使用"method"来引用一个应该绑定到一个对象的函数,而"function"则用于那些未绑定的函数 .
2在第二个片段中,将记录undefined而不是3,因为
this
默认为全局执行上下文(window
,当不处于严格模式时,否则为undefined
),当无法通过特定上下文确定时 . 在示例中window.foo
不存在因此产生undefined .3如果您查看事件队列中事件的执行情况,则会在侦听器上调用invokeGuardedCallback .
4它实际上要复杂得多 . React内部尝试在侦听器上使用
Function#apply
供自己使用,但这不起箭头功能,因为它们根本不绑定this
. 这意味着,当实际评估箭头函数内的this
时,this
将解析模块当前代码的每个执行上下文的每个词法环境 . 最终解析为具有this
绑定的执行上下文是构造函数,它具有指向当前React组件实例的this
,允许它工作 .您正在使用ES6,因此函数不会自动绑定到“this”上下文 . 您必须手动将函数绑定到上下文 .
您的函数需要绑定才能在事件处理程序中使用状态或道具
在ES5中,仅在构造函数中绑定事件处理函数,但不直接在render中绑定 . 如果直接在渲染中进行绑定,则每次组件渲染和重新渲染时都会创建一个新函数 . 所以你应该总是在构造函数中绑定它
在ES6中,使用箭头功能
当您使用箭头功能时,您无需进行绑定,也可以远离与范围相关的问题
我们必须
bind
我们的函数this
来获取类中函数的实例 . 就像在例子中一样这样
this.state
将是有效对象 .亚历山大·基尔森伯格(Alexandre Kirszenberg)是正确的,但另一个需要注意的重要事项是你的约束力 . 我已经陷入困境好几天了(可能是因为我是初学者),但与其他人不同,我知道绑定(我已经应用了)所以我无法理解为什么我还在那些错误 . 事实证明,我的绑定顺序错误 .
另一个也许是我在“this.state”中调用函数的事实,它不知道绑定,因为它碰巧在绑定行之上,
以下就是我所拥有的(顺便说一下,这是我的第一篇文章,但我认为这非常重要,因为我无法找到解决方案):