【问题标题】:Access custom component methods through ref doesnt work as expected通过 ref 访问自定义组件方法无法按预期工作
【发布时间】:2017-08-27 13:45:46
【问题描述】:

有人可以向我解释为什么在SomeClass 构造函数getLoggerClass 方法返回未定义,但在onClick() 方法返回记录器类?

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>

【问题讨论】:

    标签: javascript reactjs


    【解决方案1】:

    这是因为LoggerClass 节点上的ref 函数在SomeClassconstructor 运行时尚未执行。 constructor 在创建虚拟 DOM 时执行,而 ref 在组件实际安装到真实 DOM (more info about mounting here) 时执行。这是我认为您正在寻找的内容,相关代码在SomeClasscomponentDidMount

    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>

    【讨论】:

      【解决方案2】:

      这是罪魁祸首:

      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 第一次渲染时,将调用 constructormethod 并在其中定义: this.loggerClass as this.props.app.getLoggerClass() (请注意,您在初始化时立即调用了该函数)那又如何正在发生的是:

      • 第一个构造函数()被调用
      • 在里面你直接调用了getLoggerClass()方法,这个方法返回dom节点但是在初始化时它是undefined

      尽量不要直接调用 getLoggerClass 方法,而是稍后再调用,虽然你不需要绑定它,只需在你的 SomeClass 组件中声明一个只调用 getLoggerClass 方法的方法,如下所示:

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

      这样您就可以将时间分配给要分配的 ref。

      【讨论】:

      • 感谢您的解释,@Zevgon 使用componentDidMount 解决这个问题的方式是一个不错的方法。
      猜你喜欢
      • 2021-04-23
      • 2017-05-04
      • 1970-01-01
      • 2017-09-19
      • 1970-01-01
      • 2021-03-26
      • 1970-01-01
      • 2017-04-17
      • 1970-01-01
      相关资源
      最近更新 更多