简体   繁体   English

使用this.refs的弃用警告

[英]Deprecation warning using this.refs

I have a React component and I want to toggle a css class when clicked. 我有一个React组件,我想在点击时切换一个css类。

So I have this: 所以我有这个:

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,
    });
  }
}

This problem is that ESLint keeps telling me "this.refs" is depreciated. 这个问题是ESLint不断告诉我“this.refs”已经折旧了。

What do I do instead? 我该怎么做? How can I fix it so it's not using depreciated code? 如何修复它以便不使用折旧代码?

The Lint rule you are referring to is called no-string-refs and warns you with: 您引用的Lint规则称为no-string-refs,并通过以下方式向您发出警告:

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

You are getting this warning because have implemented the deprecated way of using refs (by using strings). 您收到此警告是因为已实现了使用refs的弃用方法(通过使用字符串)。 Depending on your React version, you can do: 根据您的React版本,您可以执行以下操作:

React 16.3 and later 反应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 and older 反应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>
  );
}

For even better readability, you could also do: 为了更好的可读性,您还可以:

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

Have a look at what the official documentation says on Refs and the DOM , and this section in particular: 看看官方文档中关于Refs和DOM的内容 ,特别是本节

Legacy API: String Refs 旧版API:字符串引用

If you worked with React before, you might be familiar with an older API where the ref attribute is a string, like "textInput" , and the DOM node is accessed as this.refs.textInput . 如果您之前使用过React,那么您可能熟悉旧的API,其中ref属性是一个字符串,如"textInput" ,DOM节点作为this.refs.textInput访问。 We advise against it because string refs have some issues , are considered legacy, and are likely to be removed in one of the future releases . 我们建议不要使用它,因为字符串引用有一些问题 ,被认为是遗留问题很可能会在未来的某个版本中删除 If you're currently using this.refs.textInput to access refs, we recommend the callback pattern instead. 如果您当前正在使用this.refs.textInput访问引用,我们建议使用回调模式。

you can try a more declarative way. 你可以尝试一种更具声明性的方式。 I changed your code to reflect this. 我更改了您的代码以反映这一点。 You just need to remind that a component will refresh and call render in every state/props change. 您只需要提醒一个组件将在每个州/道具更改时刷新并调用渲染。 So, we can create the class of your element inside render method. 因此,我们可以在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
    })
  }
}

The reason this ESLint rule exists is that string Refs are on their way out. 这个ESLint规则存在的原因是字符串Refs正在逐渐消失。 However, for the code above I would recommend to not use a Ref in the first place. 但是,对于上面的代码,我建议首先不要使用Ref。

Don't Overuse Refs 不要过度使用参考

React's advantage is that it is declarative. React的优势在于它是声明性的。 Meaning, we have state and an expression (returned JSX) of how the UI (more precisely the DOM) should look given a certain state. 意思是,我们有一个状态和一个表达式(返回JSX),表示UI(更准确地说是DOM)在给定某个状态时应该如何看待。

Whatever can be done using just state and UI expression, should be done this way. 使用状态和UI表达式可以做什么,应该这样做。 The problem with the use of a Ref in the code above is that it makes the code imperative. 在上面的代码中使用Ref的问题在于它使代码变得必不可少。 We can't understand how the DOM will look just from the JSX. 我们无法理解DOM在JSX中的外观。 Here is how you could achieve the same result in a declarative way: 以下是以声明方式实现相同结果的方法:

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>
        );
    }

}

Refs should be used when state and UI expression aren't enough, and you need access to the actual DOM. 当状态和UI表达式不够时,应该使用Refs,并且您需要访问实际的DOM。 For example, focusing on an input field, scrolling to an element, or getting the exact width and height of an element. 例如,关注输入字段,滚动到元素或获取元素的确切宽度和高度。

If you do use Refs, avoid string refs 如果您确实使用Refs,请避免使用字符串引用

String refs harm performance, aren't composable, and are on there way out. 字符串引用了损害性能,不可组合,并且在那里出路。

string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. 字符串引用有一些问题,被认为是遗留问题,很可能会在未来的某个版本中删除。 [Official React documentation] [官方反应文件]

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

Option #1: Use React.createRef 选项#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
    }

}

Option #2: Use a ref callback 选项#2:使用ref回调

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

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM