Javascript 函数未传递给按钮的原因是什么

Javascript 函数未传递给按钮的原因是什么,javascript,reactjs,relaymodern,Javascript,Reactjs,Relaymodern,我知道JavaScript的作用域,但可能我不完全理解它们,因为这段代码不起作用 此代码使用React和Relay现代框架 有两个按钮,第一个按钮位于queryRender内部,该按钮被传递到继电器现代queryRender中,第二个按钮随后被传递到继电器现代中(请参见函数渲染)。第二个正在工作,第一个没有执行clickTest功能。 (这是实际代码的简化版本) 然后我得到这样的错误:uncaughtypeerror:\u this2.clickTest不是一个函数 有人能给我解释一下为什么这段

我知道JavaScript的作用域,但可能我不完全理解它们,因为这段代码不起作用

此代码使用React和Relay现代框架

有两个按钮,第一个按钮位于
queryRender
内部,该按钮被传递到继电器现代
queryRender
中,第二个按钮随后被传递到继电器现代
中(请参见函数
渲染
)。第二个正在工作,第一个没有执行
clickTest
功能。 (这是实际代码的简化版本)

然后我得到这样的错误:uncaughtypeerror:\u this2.clickTest不是一个函数


有人能给我解释一下为什么这段代码会这样吗?

在javascript中,这段代码的含义不是在函数创建时确定的,而是在函数被调用时确定的。当QueryRenderer调用queryRender函数时,它不知道需要在类的上下文中调用它,因此
这个
将不会引用您认为它所引用的内容


您要么需要绑定queryRender函数,就像您在构造函数中使用clicktest函数一样,要么需要重新设计queryRender,这样它就不需要引用javascript中的
this

,创建函数时不确定
this
的含义,而是当它被调用时。当QueryRenderer调用queryRender函数时,它不知道需要在类的上下文中调用它,因此
这个
将不会引用您认为它所引用的内容


您要么需要绑定queryRender函数,就像在构造函数中使用clicktest函数一样,要么需要重新设计queryRender,这样它就不需要引用
,这个

箭头函数不会创建新的作用域,并且它的作用域包含执行上下文,在这种情况下,
QueryRenderer
范围中没有此函数。当您将其作为简单函数传递时,范围是否会被定义,我不知道
按钮在里面做什么。我没有使用RENEL,也不确定您是否可以引用RENEL render方法中的组件。

箭头函数不创建新的作用域,其作用域包含执行上下文,在本例中,您没有此函数的是
QueryRenderer
作用域。当您将其作为简单函数传递时,范围是否会被定义,我不知道
按钮在里面做什么。我没有使用过Rely,也不确定您是否可以从Rely render方法引用组件。

要扩展Artur和Nicholas的答案,您需要
bind()
这个,或者使用箭头函数确保
这个
引用的是组件本身。您已经有了bind方法,下面是一个arrow函数的示例,它不再需要绑定,因为arrow函数实际上并不绑定这个值,而是使用它们的父作用域

类候选扩展组件{
静态类型={
查看器:PropTypes.object
}
建造师(道具){
超级(道具)
this.clickTest=this.clickTest.bind(this)
}
单击测试(){
console.log('click works')
}    
queryRender=({error,props})=>{
如果(错误){
返回{error.message}
}否则如果(道具){
返回(
这不管用
)
}
返回加载。。。
}
渲染(){
返回(
这很有效
)
}
}

要扩展Artur和Nicholas的答案,您需要
bind()
这个或使用箭头函数来确保
这个
是指组件本身。您已经有了bind方法,下面是一个arrow函数的示例,它不再需要绑定,因为arrow函数实际上并不绑定这个值,而是使用它们的父作用域

类候选扩展组件{
静态类型={
查看器:PropTypes.object
}
建造师(道具){
超级(道具)
this.clickTest=this.clickTest.bind(this)
}
单击测试(){
console.log('click works')
}    
queryRender=({error,props})=>{
如果(错误){
返回{error.message}
}否则如果(道具){
返回(
这不管用
)
}
返回加载。。。
}
渲染(){
返回(
这很有效
)
}
}

谢谢,我没有考虑绑定
queryRender
函数。这解决了我的问题。谢谢,我没有考虑绑定
queryRender
函数。这解决了我的问题。谢谢迈克S。这实际上是非常有用的信息。谢谢迈克S。这实际上是非常有用的信息。
class Candidates extends Component {
  static propTypes = {
    viewer: PropTypes.object
  }

  constructor (props) {
    super(props)
    this.clickTest = this.clickTest.bind(this)
  }

  clickTest () {
    console.log('click works')
  }    

  queryRender ({error, props}) {
    if (error) {
      return <pre>{error.message}</pre>
    } else if (props) {
      return (
        <div>
          <Button onClick={this.clickTest}>this DOESN'T work</Button>
        </div>
      )
    }
    return <Loader active>Loading...</Loader>
  }

  render () {
    return (
      <div>
        <QueryRenderer
          environment={environment}
          query={query} 
          render={this.queryRender}
        />
        <Button onClick={this.clickTest}>this works</Button>
      </div>
    )
  }
}
<Button onClick={() => this.clickTest()}>this DOESN'T work</Button>
class Candidates extends Component {
  static propTypes = {
    viewer: PropTypes.object
  }

  constructor (props) {
    super(props)
    this.clickTest = this.clickTest.bind(this)
  }

  clickTest () {
    console.log('click works')
  }    

  queryRender = ({error, props}) => {
    if (error) {
      return <pre>{error.message}</pre>
    } else if (props) {
      return (
        <div>
          <Button onClick={this.clickTest}>this DOESN'T work</Button>
        </div>
      )
    }
    return <Loader active>Loading...</Loader>
  }

  render () {
    return (
      <div>
        <QueryRenderer
          environment={environment}
          query={query} 
          render={this.queryRender}
        />
        <Button onClick={this.clickTest}>this works</Button>
      </div>
    )
  }
}