Javascript 使用 this.refs 的弃用警告

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/43873511/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-23 02:13:19  来源:igfitidea点击:

Deprecation warning using this.refs

javascriptreactjs

提问by Chris

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?

我该怎么办?我该如何修复它以使其不使用折旧的代码?

回答by Chris

The Lint rule you are referring to is called no-string-refsand 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). Depending on your React version, you can do:

您收到此警告是因为已经实现了已弃用的使用方式refs(通过使用字符串)。根据您的 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

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

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 sectionin particular:

看看官方文档对Refs 和 DOM 的描述,特别是本节

Legacy API: String Refs

If you worked with React before, you might be familiar with an older API where the refattribute is a string, like "textInput", and the DOM node is accessed as 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.textInputto access refs, we recommend the callback pattern instead.

旧 API:字符串引用

如果您以前使用过 React,您可能熟悉旧 API,其中ref属性是一个字符串,例如 "textInput",而 DOM 节点作为 访问this.refs.textInput。我们建议不要这样做,因为字符串引用有一些问题,被认为是遗留的,并且可能会在未来的版本之一中被删除。如果您当前正在使用this.refs.textInput访问 refs,我们建议改用回调模式。

回答by Tulio Faria

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

回答by Ben Carp

The reason this ESLint rule exists is that string Refs are on their way out. However, for the code above I would recommend to not use a Ref in the first place.

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

Don't Overuse Refs

不要过度使用 Refs

React's advantage is that it is declarative. Meaning, we have state and an expression (returned JSX) of how the UI (more precisely the DOM) should look given a certain state.

React 的优势在于它是声明性的。意思是,我们有状态和一个表达式(返回的 JSX),表示给定某个状态时 UI(更准确地说是 DOM)应该如何显示。

Whatever can be done using just state and UI expression, should be done this way. The problem with the use of a Ref in the code above is that it makes the code imperative. We can't understand how the DOM will look just from the JSX. Here is how you could achieve the same result in a declarative way:

仅使用状态和 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>
        );
    }

}

Refs should be used when state and UI expression aren't enough, and you need access to the actual DOM. For example, focusing on an input field, scrolling to an element, or getting the exact width and height of an element.

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

If you do use Refs, avoid string refs

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

String refs harm performance, aren't composable, and are on there way out.

字符串 refs 会损害性能,不可组合,并且有出路。

string refs have some issues, are considered legacy, and are likely to be removed in one of the future releases. [Official React documentation]

字符串引用有一些问题,被认为是遗留的,可能会在未来的版本之一中被删除。[官方 React 文档]

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

[资源 1][1]、[资源 2][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:使用引用回调

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

}