53 votes

Avertissement de dépréciation utilisant this.refs

J'ai un composant React et je souhaite basculer vers une classe CSS lorsque l'utilisateur clique dessus.

Donc j'ai ceci:

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

Ce problème est que ESLint n'arrête pas de me dire que "this.refs" est déprécié.

Qu'est-ce que je fais à la place? Comment puis-je résoudre ce problème afin de ne pas utiliser de code amorti?

59voto

Chris Points 3970

La fibre de règle que vous faites référence s'appelle pas de chaîne de références et vous avertit avec:

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

Vous recevez cette alerte car ont mis en œuvre le obsolète façon d'utiliser refs (en utilisant des chaînes de caractères). En fonction de votre version Réagir, vous pouvez le faire:

Réagir 16.3 et plus tard

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

Réagir 16.2 et plus

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

Pour une meilleure lisibilité, vous pouvez aussi faire:

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

Jetez un oeil à ce que la documentation officielle dit sur les Refs et les DOM, et cet article en particulier:

L'héritage de l'API: Chaîne de Refs

Si vous avez travaillé avec de Réagir avant, vous pourriez être familier avec les anciennes API où l' ref de l'attribut est une chaîne de caractères, comme "textInput", et le nœud DOM est accessible en tant que this.refs.textInput. Nous déconseillé parce que la chaîne de refs ont certains problèmes, sont considérés comme l'héritage, et sont susceptibles d'être retirés dans une des prochaines versions. Si vous êtes actuellement en utilisant this.refs.textInput d'accès refs, nous recommander le rappel du motif à la place.

1voto

Ben Carp Points 1515

La raison de ce ESLint règle existe, c'est que la chaîne de Refs sont sur leur chemin. Cependant, pour le code ci-dessus, je recommande de ne pas utiliser une Ref en premier lieu.

Ne multipliez pas les Refs

Réagir l'avantage est qu'il est déclaratif. Sens, nous avons de l'état et de l'expression (renvoyée JSX) de la façon dont l'INTERFACE utilisateur (plus précisément les DOM) devrait ressembler à un certain état.

Tout ce qui peut être fait en utilisant seulement de l'état de l'INTERFACE et de l'expression, doit être fait de cette façon. Le problème avec l'utilisation d'une Ref dans le code ci-dessus est qu'elle rend le code impératif. Nous ne pouvons pas comprendre comment les DOM cherchera simplement à partir de la JSX. Voici comment vous pouvez obtenir le même résultat de manière déclarative:

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

}

Les références doivent être utilisés lors de l'état de l'INTERFACE et de l'expression ne sont pas assez, et vous avez besoin d'accéder à un autre DOM. Par exemple, en se concentrant sur un champ de saisie, le défilement d'un élément, ou d'obtenir la largeur exacte et la hauteur d'un élément.

Si vous utilisez des Refs, éviter chaîne de refs

Chaîne de refs nuire à la performance, ne sont pas composable, et sont sur il y a moyen de sortir.

chaîne de refs ont des problèmes, sont considérés comme un héritage, et sont susceptibles d' être retiré dans une des prochaines versions. [Officiel de Réagir documentation]

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

Option #1: Utilisation De Réagir.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: Utilisez une ref de rappel

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

}

0voto

Tulio Faria Points 354

vous pouvez essayer une méthode plus déclarative. J'ai changé votre code pour refléter cela. Il vous suffit de rappeler qu'un composant actualisera et appellera le rendu à chaque changement d'état / d'accessoire. Nous pouvons donc créer la classe de votre élément dans la méthode de rendu.

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

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X