通过ref访问自定义组件方法无法按预期工作

时间:2017-08-27 13:45:46

标签: javascript reactjs

有人可以向我解释为什么SomeClass构造函数getLoggerClass方法返回undefined,但在onClick()方法内它返回logger类?

class App extends React.Component {

 constructor(props){
  super(props)
  this.getLoggerClass = this.getLoggerClass.bind(this)
 }
 
  render(){
  
   return(
   
    <div>
      <LoggerClass ref={(c)=>{this.loggerClass = c}}/>
      <SomeClass app={this} />
    </div>
   
   ) 
  
  }
  
  getLoggerClass(){
    return this.loggerClass
  
  }

}

class SomeClass extends React.Component {
  
  constructor(props){
  super(props)

    this.loggerClass = this.props.app.getLoggerClass()
    console.log(this.loggerClass)
    
    this.onClick = this.onClick.bind(this)
  }
  
  render(){
  
   return <button onClick={this.onClick}>click</button>
  
  }
  
  onClick(){

    console.log(this.props.app.getLoggerClass().console)
    
  }

}

class LoggerClass extends React.Component {

  render(){
    return <div></div>
  }
  
  console(v){
    console.log(v)
  }
  
  test(){}

}


ReactDOM.render(<App />,document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>

<div id="app"></div>

2 个答案:

答案 0 :(得分:1)

这是罪魁祸首:

constructor(props){
super(props)

this.loggerClass = this.props.app.getLoggerClass()
console.log(this.loggerClass)

this.onClick = this.onClick.bind(this)
}

要了解问题,您必须了解,引用mdn,The constructor method is a special method for creating and initializing an object created within a class.

基本上,这个构造函数方法用于初始化,因此在类生命期间只调用一次。因此,当您的SomeClass首次渲染时,调用constructor方法并在其中定义:this.loggerClass as this.props.app.getLoggerClass()(请注意,您在init处立即调用了该函数所以发生的事情就是:

  • 第一个构造函数()被称为
  • 在其中你直接调用 getLoggerClass()方法,此方法返回dom节点,但在初始时它是undefined

尝试不直接调用getLoggerClass方法但稍后调用它,你不需要绑定它,只需在SomeClass组件中声明一个只调用getLoggerClass方法的方法:

callGetLoggerClassFromProps() {
  return this.props.app.getLoggerCLass()
} 

这样你就可以给ref分配时间了。

答案 1 :(得分:1)

这是因为ref节点上的LoggerClass函数在constructor运行SomeClass时尚未执行。创建虚拟DOM时会执行constructor,而当组件实际安装到真实DOM(more info about mounting here)时会执行ref。以下是我认为您正在寻找的内容,以及SomeClass的{​​{1}}中的相关代码:

componentDidMount
class App extends React.Component {

 constructor(props){
  super(props)
  this.getLoggerClass = this.getLoggerClass.bind(this)
 }
 
  render(){
  
   return(
   
    <div>
      <LoggerClass ref={(c)=>{this.loggerClass = c}}/>
      <SomeClass app={this} />
    </div>
   
   ) 
  
  }
  
  getLoggerClass(){
    return this.loggerClass
  
  }

}

class SomeClass extends React.Component {
  
  constructor(props){
  super(props)
    
    this.onClick = this.onClick.bind(this)
  }
  
  componentDidMount() {
    this.loggerClass = this.props.app.getLoggerClass()
    console.log('in mounted', this.loggerClass.console)
  }
  
  render(){
  
   return <button onClick={this.onClick}>click</button>
  
  }
  
  onClick(){

    console.log(this.props.app.getLoggerClass().console)
    
  }

}

class LoggerClass extends React.Component {

  render(){
    return <div></div>
  }
  
  console(v){
    console.log(v)
  }
  
  test(){}

}


ReactDOM.render(<App />,document.getElementById('app'))