Tengo un componente React y quiero alternar una clase css cuando se hace clic.
Así que tengo esto:
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"> </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, }); } }Este problema es que ESLint sigue diciéndome que "this.refs" está depreciado.
¿Qué hago en su lugar? ¿Cómo puedo arreglarlo para que no use código depreciado?
La regla de Lint a la que te refieres se llama no-string-refs y te advierte con:
"Using string literals in ref attributes is deprecated (react/no-string-refs)" Está recibiendo esta advertencia porque ha implementado la forma obsoleta de usar refs (usando cadenas). Dependiendo de su versión de React, puede hacer:
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"> </span></div> </div> ); } 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"> </span></div> </div> ); }Para una legibilidad aún mejor, también podría hacer:
render() { let myRef = (el) => this.btnRef = el; return ( <div> <div onClick={this.addVote}><span ref={myRef} className="glyphicon"> </span></div> </div> ); }Eche un vistazo a lo que dice la documentación oficial sobre Refs y el DOM , y esta sección en particular:
API heredada: referencias de cadena
Si trabajó con React antes, es posible que esté familiarizado con una API más antigua donde el atributo
refes una cadena, como"textInput", y se accede al nodo DOM comothis.refs.textInput. No lo recomendamos porque las referencias de cadena tienen algunos problemas , se consideran heredadas y es probable que se eliminen en una de las versiones futuras . Si actualmente está utilizandothis.refs.textInputpara acceder a las referencias, le recomendamos el patrón de devolución de llamada en su lugar.
La razón por la que existe esta regla ESLint es que las referencias de cadena están a punto de desaparecer. Sin embargo, para el código anterior recomendaría no usar una Ref en primer lugar.
La ventaja de React es que es declarativo. Es decir, tenemos un estado y una expresión (JSX devuelto) de cómo debería verse la interfaz de usuario (más precisamente, el DOM) en un determinado estado.
Cualquier cosa que se pueda hacer usando solo el estado y la expresión de la interfaz de usuario, debe hacerse de esta manera. El problema con el uso de una Ref en el código anterior es que hace que el código sea imperativo. No podemos entender cómo se verá el DOM solo desde el JSX. Así es como podría lograr el mismo resultado de manera declarativa:
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> ); } }Las referencias deben usarse cuando el estado y la expresión de la interfaz de usuario no son suficientes y necesita acceso al DOM real. Por ejemplo, enfocarse en un campo de entrada, desplazarse a un elemento u obtener el ancho y el alto exactos de un elemento.
Las referencias de cadena dañan el rendimiento, no se pueden componer y están a punto de desaparecer.
las referencias de cadena tienen algunos problemas, se consideran heredadas y es probable que se eliminen en una de las versiones futuras. [Documentación oficial de React]
[recurso1][1], [recurso2][1]
Opción #1: Usar 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 } }Opción n. ° 2: use una devolución de llamada de referencia
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 }puedes probar una forma más declarativa. Cambié tu código para reflejar esto. Solo necesita recordar que un componente se actualizará y llamará al renderizado en cada cambio de estado/accesorios. Entonces, podemos crear la clase de su elemento dentro del método de renderizado.
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}> </span></div> </div> ); } handleClick() { this.setState({ clicked: !this.state.clicked }) } }