【问题标题】:Deprecation warning using this.refs使用 this.refs 的弃用警告
【发布时间】:2017-10-07 23:35:14
【问题描述】:

我有一个 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 一直告诉我“this.refs”被贬值了。

我该怎么做?如何修复它,使其不使用折旧代码?

【问题讨论】:

  • 顺便说一句,在您的 setState 中,您可以在不使用 this 的情况下将它们分配为 true 或 false...我会使用 onClick={setButtonState} 然后在函数内部您可以简单地设置状态和随意切换。

标签: javascript reactjs


【解决方案1】:

您所指的 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,你可能会 熟悉 ref 属性是字符串的旧 API,例如 "textInput",DOM 节点以this.refs.textInput 访问。我们 建议不要这样做,因为字符串引用有some issues,被认为是 旧版,并且可能会在未来的某个版本中被删除。如果 您目前正在使用this.refs.textInput 访问参考文献,我们 推荐使用回调模式。

【讨论】:

  • 如何访问componentWillUnmount()生命周期钩子中的引用?
  • @essaji,就像您在应用程序中的任何位置一样。例如,在我上面的 sn-p 中,您可以使用 this.btnRef 访问它。
【解决方案2】:

您可以尝试一种更具声明性的方式。我更改了您的代码以反映这一点。您只需要提醒组件将在每次状态/道具更改时刷新并调用渲染。因此,我们可以在 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
    })
  }
}

【讨论】:

    【解决方案3】:

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

    不要过度使用 Refs

    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 时,应该使用 Refs。例如,关注输入字段、滚动到元素或获取元素的确切宽度和高度。

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

    String refs 会损害性能,不可组合,并且即将淘汰。

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

    [资源1][1],[资源2][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:使用 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
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-04
      • 1970-01-01
      • 2021-05-20
      • 2017-03-23
      • 1970-01-01
      • 2017-09-04
      相关资源
      最近更新 更多