¿Cómo acceder a un elemento DOM en React? ¿Cuál es el equivalente de document.getElementById () en React

203

¿Cómo selecciono ciertas barras en react.js?

Este es mi código:

var Progressbar = React.createClass({
    getInitialState: function () {
        return { completed: this.props.completed };
    },
    addPrecent: function (value) {
        this.props.completed += value;
        this.setState({ completed: this.props.completed });
    },

    render: function () {

        var completed = this.props.completed;
        if (completed < 0) { completed = 0 };


        return (...);
    }

Quiero usar este componente Reaccionar:

var App = React.createClass({
    getInitialState: function () {

        return { baction: 'Progress1' };
    },
    handleChange: function (e) {
        var value = e.target.value;
        console.log(value);
        this.setState({ baction: value });
    },
    handleClick10: function (e) {
        console.log('You clicked: ', this.state.baction);
        document.getElementById(this.state.baction).addPrecent(10);
    },
    render: function () {
        return (
            <div class="center">Progress Bars Demo
            <Progressbar completed={25} id="Progress1" />
                <h2 class="center"></h2>
                <Progressbar completed={50} id="Progress2" />
                <h2 class="center"></h2>
                <Progressbar completed={75} id="Progress3" />
                <h2 class="center"></h2>
                <span>
                    <select name='selectbar' id='selectbar' value={this.state.baction} onChange={this.handleChange}>
                        <option value="Progress1">#Progress1</option>
                        <option value="Progress2">#Progress2</option>
                        <option value="Progress3">#Progress3</option>
                    </select>
                    <input type="button" onClick={this.handleClick10} value="+10" />
                    <button>+25</button>
                    <button>-10</button>
                    <button>-25</button>
                </span>
            </div>
        )
    }
});

Quiero ejecutar la función handleClick10 y realizar la operación para mi barra de progreso seleccionada. Pero el resultado que obtengo es:

 You clicked:  Progress1
 TypeError: document.getElementById(...) is null

¿Cómo selecciono cierto elemento en react.js?

usuario504909
fuente

Respuestas:

214

Puede hacerlo especificando el ref

EDITAR: en react v16.8.0 con componente funcional, puede definir una referencia con useRef. Tenga en cuenta que cuando especifica una referencia en un componente funcional, debe usar React.forwardRef para reenviar la referencia al elemento DOM que se utiliza useImperativeHandlepara exponer ciertas funciones desde dentro del componente funcional

Ex:

const Child1 = React.forwardRef((props, ref) => {
    return <div ref={ref}>Child1</div> 
});

const Child2 = React.forwardRef((props, ref) => {
    const handleClick= () =>{};
    useImperativeHandle(ref,() => ({
       handleClick
    }))
    return <div>Child2</div> 
});
const App = () => {
    const child1 = useRef(null);
    const child2 = useRef(null);

    return (
        <>
           <Child1 ref={child1} />
           <Child1 ref={child1} />
        </>
    )
}

EDITAR:

En React 16.3+ , use React.createRef()para crear su referencia:

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  render() {
    return <div ref={this.myRef} />;
  }
}

Para acceder al elemento, use:

const node = this.myRef.current;

DOC para usar React.createRef ()


EDITAR

Sin embargo, Facebook desaconseja porque las referencias de cadena tienen algunos problemas, se consideran heredadas y es probable que se eliminen en una de las versiones futuras.

De los documentos:

API heredada: referencias de cadena

Si trabajó con React anteriormente, puede estar familiarizado con una API anterior donde el atributo ref es una cadena, como "textInput", y se accede al nodo DOM como this.refs.textInput. No lo recomendamos porque las referencias de cadenas tienen algunos problemas, se consideran heredadas y es probable que se eliminen en una de las versiones futuras. Si actualmente usa this.refs.textInput para acceder a las referencias, le recomendamos el patrón de devolución de llamada.

Una forma recomendada para React 16.2 y anteriores es utilizar el patrón de devolución de llamada:

<Progressbar completed={25} id="Progress1" ref={(input) => {this.Progress[0] = input }}/>

<h2 class="center"></h2>

<Progressbar completed={50} id="Progress2" ref={(input) => {this.Progress[1] = input }}/>

  <h2 class="center"></h2>

<Progressbar completed={75} id="Progress3" ref={(input) => {this.Progress[2] = input }}/>

DOC para usar la devolución de llamada


Incluso las versiones anteriores de referencias definidas reaccionan usando una cadena como la siguiente

<Progressbar completed={25} id="Progress1" ref="Progress1"/>

    <h2 class="center"></h2>

    <Progressbar completed={50} id="Progress2" ref="Progress2"/>

      <h2 class="center"></h2>

    <Progressbar completed={75} id="Progress3" ref="Progress3"/>

Para obtener el elemento simplemente haz

var object = this.refs.Progress1;

Recuerde usar thisdentro de un bloque de función de flecha como:

print = () => {
  var object = this.refs.Progress1;  
}

y así...

Shubham Khatri
fuente
55
Facebook desaconseja este enfoque. Ver aquí facebook.github.io/react/docs/refs-and-the-dom.html
Dmitry
44
@dmitrymar Como puedo ver, la página anterior está escrita para v15.4.2 en adelante y supongo que esto no estaba allí antes cuando escribí la respuesta. De todos modos editó la respuesta con el enfoque correcto
Shubham Khatri
2
@ MattSidor, gracias por la edición, me ahorraste algo de tiempo :-)
Shubham Khatri
Um, pregunta qué pasa si no puedo acceder a través de "this", ¿qué pasa si el componente que necesito es una instancia de otra clase? (es decir, otro componente de reacción del niño dentro del componente padre)
akshay kishore
@akshaykishore Debería pasar la referencia hacia abajo con otro nombre, como innerRef, y pasarla al componente deseado
Shubham Khatri,
37

Para obtener el elemento react, debe usar refy dentro de la función puede usar el ReactDOM.findDOMNodemétodo.

Pero lo que más me gusta hacer es llamar al árbitro justo dentro del evento

<input type="text" ref={ref => this.myTextInput = ref} />

Este es un buen enlace para ayudarte a descubrirlo.

EQuimper
fuente
2
Esta es la forma correcta de hacer esto. Esto agrega una referencia al elemento en el objeto / clase que simplemente puede usar this.myTextInputpara acceder.
Sam Parmenter
1
¿Cómo puedo hacer esto con un elemento creado dinámicamente?
Sagar Kodte
Llamar React.findDOMNodeme dareact__WEBPACK_IMPORTED_MODULE_0___default.a.findDOMNode is not a function
James Poulose
@JamesPoulose asegúrate de no estar ejecutando en modo estricto, porque reaccionar no te permitirá usarlo React.findDOMNodeen modo estricto.
Limpuls
12

Usted puede reemplazar

document.getElementById(this.state.baction).addPrecent(10);

con

this.refs[this.state.baction].addPrecent(10);


  <Progressbar completed={25} ref="Progress1" id="Progress1"/>
Piyush.kapoor
fuente
3
¿Cómo puedo hacer esto con un elemento creado dinámicamente?
Sagar Kodte
1

Como React usa el código JSX para crear un HTML, no podemos hacer referencia a dom utilizando métodos de regulación como documment.querySelector o getElementById.

En cambio, podemos usar el sistema de referencia React para acceder y manipular Dom como se muestra en el siguiente ejemplo:

constructor(props){

    super(props);
    this.imageRef = React.createRef(); // create react ref
}

componentDidMount(){

    **console.log(this.imageRef)** // acessing the attributes of img tag when dom loads
}


render = (props) => {

const {urls,description} = this.props.image;
    return (

            <img
             **ref = {this.imageRef} // assign the ref of img tag here**
             src = {urls.regular} 
             alt = {description}
             />

        );

}

}

Nikhil Kamani
fuente
1
Esto no es verdad. Puede agregar una identificación al elemento img, tomarla usando document.getElementById y, en la mayoría de los casos, funcionará bien. Puede causar problemas / hacer que su código sea más difícil de depurar, pero reaccionar / jsx no lo haga para que NO pueda usar métodos Dom nativos
adam tropp