使用this.refs

时间:2017-05-09 15:08:44

标签: javascript reactjs

我有一个React组件,我想在点击时切换一个css类。

所以我有这个:

export class myComponent extends React.Component {
  constructor() {
    super();
    this.state = { clicked: false };
    this.handleClick = this.handleClick.bind(this);
  }

  render() {
    return (
      <div>
        <div onClick={this.clicked}><span ref="btn" className="glyphicon">&nbsp;</span></div>
      </div>
    );
  }

  handleClick() {
    this.refs.btn.classList.toggle('active');
  }

  componentDidMount() {
    this.refs.btn.addEventListener('click', this.handleClick);
    this.setState({
      clicked: this.state.clicked = true,
    });
  }

  componentWillUnmount() {
    this.refs.btn.removeEventListener('click', this.handleClick);
    this.setState({
      clicked: this.state.clicked = false,
    });
  }
}

这个问题是ESLint一直告诉我&#34; this.refs&#34;折旧。

我该怎么做?如何修复它以免它使用折旧代码?

3 个答案:

答案 0 :(得分:41)

您所指的Lint规则称为no-string-refs,并通过以下方式向您发出警告:

"Using string literals in ref attributes is deprecated (react/no-string-refs)"

您收到此警告是因为已实施使用refs的弃用方法(通过使用字符串)。根据您的React版本,您可以执行以下操作:

React 16.3及更高版本

constructor() {
  super();
  this.btnRef= React.createRef();
  this.state = { clicked: false };
  this.handleClick = this.handleClick.bind(this);
}

render() {
  return (
    <div>
      <div onClick={this.addVote}><span ref={this.btnRef} className="glyphicon">&nbsp;</span></div>
    </div>
  );
}

React 16.2及更早版本

constructor() {
  super();
  this.btnRef;  //not necessary to declare the variable here, but I like to make it more visible.
  this.state = { clicked: false };
  this.handleClick = this.handleClick.bind(this);
}

render() {
  return (
    <div>
      <div onClick={this.addVote}><span ref={(el) => this.btnRef = el} className="glyphicon">&nbsp;</span></div>
    </div>
  );
}

为了更好的可读性,你也可以这样做:

render() {
  let myRef = (el) => this.btnRef = el;
  return (
    <div>
      <div onClick={this.addVote}><span ref={myRef} className="glyphicon">&nbsp;</span></div>
    </div>
  );
}

查看官方文档在Refs and the DOM上所说的内容,特别是this section

  

旧版API:字符串引用

     

如果您之前使用过React,那么您可能会   熟悉较旧的API,其中ref属性是一个字符串,如   "textInput",DOM节点作为this.refs.textInput访问。我们   建议反对它,因为字符串引用有some issues,被认为是   旧版和可能会在以后的某个版本中删除。如果   您目前正在使用this.refs.textInput来访问裁判,我们   建议使用回调模式。

答案 1 :(得分:0)

你可以尝试一种更具声明性的方式。我更改了您的代码以反映这一点。您只需要提醒一个组件将在每个州/道具更改时刷新并调用渲染。因此,我们可以在render方法中创建元素的类。

import React from 'react'

export default class myComponent extends React.Component {
  constructor() {
    super();
    this.state = { clicked: false };
    this.handleClick = this.handleClick.bind(this);
  }

  render() {
    let btnClass = 'glyphicon'
    if(this.state.clicked){
      btnClass+=' active'
    }
    return (
      <div>
        <div onClick={this.handleClick}><span ref="btn" className={btnClass}>&nbsp;</span></div>
      </div>
    );
  }

  handleClick() {
    this.setState({
      clicked: !this.state.clicked
    })
  }
}

答案 2 :(得分:0)

存在此ESLint规则的原因是字符串Ref即将退出。但是,对于上面的代码,我建议首先不要使用Ref。

不要滥用引用

React的优势在于它是声明性的。意思是,我们有一个状态和一个表达式(返回的JSX),该表达式表示在给定特定状态下UI(更确切地说是DOM)的外观。

仅使用状态和UI表达式可以完成的任何操作,都应以这种方式完成。在上面的代码中使用Ref的问题在于,使代码变得势在必行。我们仅从JSX中就无法理解DOM的外观。您可以通过以下方法以声明的方式获得相同的结果:

export class myComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = { 
            active: false 
        };
    }

    handleClick = () => {  // with arrow function there is no need for binding. 
        this.setState(
            prevState => {
                return {
                    active: !prevState.active
                }
            }
        )
    }

    render() {
        return (
            <div>
                <span 
                    onClick={this.handleClick} 
                    className={`glyphicon ${this.state.active && "active"}`}
                >
                    Hello World
                </span>
            </div>
        );
    }

}

当状态和UI表达式不够用并且您需要访问实际DOM时,应使用引用。例如,专注于输入字段,滚动到元素或获取元素的确切宽度和高度。

如果您确实使用引用,请避免使用字符串引用

字符串引用会损害性能,不可组合且无法解决。

  

字符串引用存在一些问题,被认为是旧问题,并且可能   在将来的版本之一中删除。 [官方React文档]

[resource1] [1],[resource2] [1]

选项1:使用React.createRef

class MyComponent extends Component {

    constructor(props) {
        super(props)
        this.myRef = React.createRef() // create a ref object 
    }

    render() {
        return <div ref={this.myRef}></div> // Attach the ref property to a dom element
    }

}

选项2:使用引用回调

class MyComponent extends Component {

    constructor(props){    // Optional, declare a class field
        super(props)
        this.myRef=null    
    }

    render() {
        return <div ref={ (ref) => this.myRef=ref }></div>
    }   // Attach the dom element to a class field

}