Poder hacer referencia de un elemento del DOM o de un componente de clase (class components porque tiene instancia)
📖 Documentación | 🎬 Como usar react refs _ Leo Medina |
- Controlar focus, selección de textos o reproducción de medios
- Integracion con bibliotecas DOM de terceros
El atributo ref es especial y solo se puede usar en componentes de clase y elementos del DOM
"React asignará a la propiedad current el elemento del DOM cuando el componente sea montado, y la asignará de nuevo null cuando sea desmontado. La referencia es actualizada antes de los métodos componentDidMount o componentDidUpdate"
No puedes hacer uso de referencias de componentes de función debido a que no tienen instancias.
- El método createRef devuelve un objeto que en la clave current tiene la referencia al elemento DOM
class CreateRef extends React.Component {
/* Crea una referencia(crea un objeto) para guardar el elemento textInput del DOM */
inputRef = React.createRef();
...
- Pasamos la referencia en el atributo ref del elemento que queremos
return (
<>
<input type="text" ref={this.inputRef} />
</>
);
- Podemos usar esa referencia en cualquier lugar de la clase y para hacer referencia al elemento DOM debemos acceder a la clave curent
class CreateRef extends React.Component {
//...
handleFocus = () => {
if (this.inputRef) {
console.log("Focus");
/* Estamos accediendo la propiedad "current" para obtener el nodo del DOM */
this.inputRef.current.focus();
}
};
//...
render() {
return (
<>
<h2>
{/* ... */}
<input type="text" ref={this.inputRef} />
<button onClick={this.handleFocus}>Focus</button>
</h2>
</>
);
}
}
Podemos hacer un ref a componentes de clase Personalizados y poder hacer uso de sus métodos en el padre.
- En el hijo tenemos el ref y el método que hacen focus
class CustomTextInput extends React.Component {
/* Crea una referencia(crea un objeto) para guardar el elemento textInput del DOM */
inputRef = React.createRef();
handleFocus = () => {
if (this.inputRef) {
console.log("Focus");
/* Estamos accediendo la propiedad "current" para obtener el nodo del DOM */
this.inputRef.current.focus();
}
};
render() {
return (
<>
<h2>
<input type="text" ref={this.inputRef} />
</h2>
</>
);
}
}
- Hacemos uso del método handleFocus en el padre para simular un click y que se haga focus al montar el componente
class CreateRefClassComponent extends React.Component {
/* Crea una referencia(crea un objeto) para guardar la instancia del componente de clase la cual nos permitirá acceder a sus métodos*/
autofocusRef = React.createRef();
componentDidMount() {
/* Podemos tener acceso a sus métodos que estan almacenados en la propiedad current */
this.autofocusRef.current.handleFocus();
}
render() {
return (
<>
<CustomTextInput />
<CustomTextInput ref={this.autofocusRef} />
</>
);
}
}
React llamara al callback del ref con el elemento del DOM cuando el componente sea montado, y lo llamara con null cuando este se desmonte. Se asegura que las referencias serán actualizadas antes que el componentDidMount o el componentDidUpdate sean ejecutados.
- Pasamos una función al prop ref esta funcion recibirá al elemento como argumento
return (
<>
<input type="text" ref={this.setInputTextRef} />
<button onClick={this.handleFocus}>focus</button>
</>
);
- almacenamos el elemento en una propiedad y podemos hacer uso de el en la clase
class CallbackRef extends React.Component {
inputText = null;
/* Esta funcion recibe como parámetro el elemento del DOM y podemos asignarlo a una propiedad*/
setInputTextRef = (element) => {
this.inputText = element;
};
handleFocus = () => {
/* comprobamos que el elemento este montado en el DOM */
if (this.inputText) {
console.log("focus");
this.inputText.focus();
}
};
...
}
Se encuentra actualmente deprecado y no se debe de usar
Solo funciona en class components
- Agregamos una prop llamada ref con un string que viene a ser el nombre del ref que usaremos para acceder al elemento
return (
<>
<input type="text" ref="nameRef" />
<button onClick={this.handleFocus}>focus</button>
</>
);
- Podemos hacer uso de métodos que existen en el elemento nativo
handleFocus = () => {
console.log("click in focus");
console.log(this.refs.nameRef);
this.refs.nameRef.focus();
};
Reenvio de ref es una característica opcional que permite pasar ref entre componentes
Solo funciona para componentes funcionales y a partir de react 16.3
- En el componente padre creamos la ref y la pasamos como parámetro ref al componente funcional hijo
const GrandParent = () => {
/* Creamos la ref */
const nameRef = React.createRef();
return (
<div>
{/* La pasamos al compoennte hijo */}
<CustomComponent ref={nameRef} />
</div>
);
};
- Envolvemos el componente hijo(componente funcional) con React.forwardRef el cual recibe una funcion que tiene como segundo parámetro el ref y la asignamos al elemento DOM o componente de clase que queremos referenciar.
const CustomComponent = React.forwardRef((props, ref) => {
return (
<div>
<input type="text" ref={ref} />
</div>
);
});
Podemos pasar una prop con un nombre alternativo a ref
- Creamos la ref en el componente padre y la enviamos al hijo como una prop con un nombre diferente a ref
class GrandParent extends React.Component {
constructor(props) {
super(props);
/* Creamos el ref */
this.nameRef = React.createRef();
}
render() {
/* LO enviamos en una prop */
return <Parent inputRef={this.nameRef} />;
}
}
- Asignamos la ref que pasamos al elemento o clase en su atributo ref
const CustomComponent = (props) => {
return (
<div>
{/* Asignamos la prop recibida */}
<input type="text" ref={props.inputRef} />
</div>
);
};
Podemos pasar una prop con un nombre alternativo a ref
- Creamos el callback en el componente padre y la enviamos al hijo como una prop con un nombre diferente a ref
class GrandParent extends React.Component {
nameRef = null;
callbackRef = (element) => {
this.nameRef = element;
};
render() {
/* LO enviamos en una prop */
return <Parent inputRef={this.callbackRef} />;
}
}
- Asignamos la ref que pasamos al elemento o clase en su atributo ref
const CustomComponent = (props) => {
return (
<div>
{/* Asignamos la prop recibida */}
<input type="text" ref={props.inputRef} />
</div>
);
};