2

Can someone explain to me why in SomeClass constructor getLoggerClass method returns undefined,but inside onClick() method it returns logger class?

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>
Jan Ciołek
  • 1,796
  • 3
  • 17
  • 32

2 Answers2

1

Here is the culprit :

constructor(props){
super(props)

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

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

To understand the problem you must understand the, quote mdn, The constructor method is a special method for creating and initializing an object created within a class.

So basically, this constructor method is used to initialize, and so it is called only one time during the class life. So when your SomeClass first renders, the constructormethod is called and in it you define : this.loggerClass as this.props.app.getLoggerClass() (notice here that you called the function immediately at init time) so what is happening is that :

  • first constructor() is called
  • in it you called directly the getLoggerClass() method, this method returns the dom node but at init time it is undefined

Try to not call the getLoggerClass method directly but call it later, you do not need to bind it though, just declare in your SomeClass component a method that just calls the getLoggerClass method like so :

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

this way you give the time to the ref to be assigned.

MaieonBrix
  • 1,584
  • 2
  • 14
  • 25
1

It's because the ref function on the LoggerClass node hasn't been executed by the time the constructor of SomeClass gets run. The constructor gets executed when creating the virtual DOM, whereas the ref gets executed when the component actually gets mounted to the real DOM (more info about mounting here). Here's what I think you're looking for, with the relevant code in SomeClass's 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'))
<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>
Zevgon
  • 556
  • 4
  • 13