Las referencias permiten acceder a los nodos DOM directamente desde React. Esto resulta útil en situaciones en las que, solo como un ejemplo, desea cambiar el elemento secundario de un componente. Digamos que quiere cambiar el valor de un <input>
elemento, pero sin usar accesorios o volver a renderizar todo el componente.
Ese es el tipo de cosas para las que los árbitros son buenos y en lo que profundizaremos en esta publicación.
ACTUALIZAR: useRef Hook
Esto fue escrito originalmente antes de React Hooks. En caso de que eso sea lo que estás buscando aquí, aquí tienes un ejemplo rápido:
Ver la pluma
Reaccionar useRef Hook por CodePen (@codepen)
en CodePen.
El resto de esta publicación entrará en referencias, lo que sigue siendo relevante en el qué y el por qué de las referencias.
Cómo crear una referencia
createRef()
es una nueva API que se envió con React 16.3. Puede crear una referencia llamando React.createRef()
y adjuntarle un elemento React usando el ref
atributo en el elemento.
class Example extends React.Component {
constructor(props) {
super(props)
// Create the ref
this.exampleRef = React.createRef()
}
render() {
return (
<div>
// Call the ref with the `ref` attribute
<input type="text" ref={this.exampleRef} />
</div>
)
}
}
Podemos “referirnos” al nodo de la ref creado en el método de render con acceso al atributo actual de la ref. Del ejemplo anterior, eso sería this.exampleRef.current
.
He aquí un ejemplo:
Consulte Pen React Ref – createRef de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
class App extends React.Component {
constructor(props) {
super(props)
// Create the ref
this.textInput = React.createRef();
this.state = {
value: ''
}
}
// Set the state for the ref
handleSubmit = e => {
e.preventDefault();
this.setState({ value: this.textInput.current.value})
};
render() {
return (
<div>
<h1>React Ref - createRef</h1>
// This is what will update
<h3>Value: {this.state.value}</h3>
<form onSubmit={this.handleSubmit}>
// Call the ref on <input> so we can use it to update the <h3> value
<input type="text" ref={this.textInput} />
<button>Submit</button>
</form>
</div>
);
}
}
Cómo podría ir hacia abajo una conversación entre un componente hijo y un elemento que contiene la referencia.
Este es un componente que procesa texto, un campo de entrada y un botón. La referencia se crea en el constructor y luego se adjunta al elemento de entrada cuando se renderiza. Cuando se hace clic en el botón, el valor enviado desde el elemento de entrada (que tiene la referencia adjunta) se utiliza para actualizar el estado del texto (contenido en una etiqueta H3). Hacemos uso de this.textInput.current.value
para acceder al valor y el nuevo estado se muestra en la pantalla.
Pasando una función de devolución de llamada a ref
React te permite crear una referencia pasando una función de devolución de llamada al ref
atributo de un componente. Así es como se ve:
<input type="text" ref={element => this.textInput = element} />
La devolución de llamada se utiliza para almacenar una referencia al nodo DOM en una propiedad de instancia. Cuando queremos hacer uso de esta referencia, accedemos a ella mediante:
this.textInput.value
Veamos cómo se ve eso en el mismo ejemplo que usamos antes.
Consulte Pen React Ref – Callback Ref de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
class App extends React.Component {
state = {
value: ''
}
handleSubmit = e => {
e.preventDefault();
this.setState({ value: this.textInput.value})
};
render() {
return (
<div>
<h1>React Ref - Callback Ref</h1>
<h3>Value: {this.state.value}</h3>
<form onSubmit={this.handleSubmit}>
<input type="text" ref={element => this.textInput = element} />
<button>Submit</button>
</form>
</div>
);
}
}
Cuando haga uso de la devolución de llamada como lo hicimos anteriormente, React llamará a la devolución de llamada de referencia con el nodo DOM cuando el componente se monte, cuando el componente se desmonte, lo llamará con nulo.
También es posible pasar ref de un componente padre a un componente hijo usando devoluciones de llamada.
Consulte Pen React Ref – Callback Ref 2 de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Creemos nuestro componente “tonto” que generará una entrada simple:
const Input = props => {
return (
<div>
<input type="text" ref={props.inputRef} />
</div>
);
};
Este componente está esperando inputRef
props de su componente principal que luego se usa para crear una referencia al nodo DOM.
Aquí está el componente principal:
class App extends React.Component {
state = {
value: ''
};
handleSubmit = event => {
this.setState({ value: this.inputElement.value });
};
render() {
return (
<div>
<h1>React Ref - Callback Ref</h1>
<h3>Value: {this.state.value}</h3>
<Input inputRef={el => (this.inputElement = el)} />
<button onClick={this.handleSubmit}>Submit</button>
</div>
);
}
}
En el componente Aplicación, queremos obtener el texto que se ingresa en el campo de entrada (que está en el componente secundario) para poder renderizarlo. La referencia se crea usando una devolución de llamada como hicimos en el primer ejemplo de esta sección. La clave radica en cómo accedemos al DOM del elemento de entrada en el componente de entrada desde el componente de la aplicación. Si miras de cerca, accedemos a él usando this.inputElement
. Entonces, al actualizar el estado del valor en el componente de la aplicación, obtenemos el texto que se ingresó en el campo de entrada usando this.inputElement.value
.
El atributo ref como una cadena
Este es el vieja forma de crear una referencia y es probable que se elimine en una versión futura debido a algunos problemas asociados con ella. El equipo de React desaconseja su uso, llegando incluso a etiquetarlo como “heredado” en la documentación. Lo incluimos aquí de todos modos porque existe la posibilidad de que lo encuentre en una base de código.
Consulte Pen React Ref – String Ref de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Volviendo a nuestro ejemplo de una entrada cuyo valor se usa para actualizar el valor del texto en el envío:
class App extends React.Component {
state = {
value: ''
}
handleSubmit = e => {
e.preventDefault();
this.setState({ value: this.refs.textInput.value})
};
render() {
return (
<div>
<h1>React Ref - String Ref</h1>
<h3>Value: {this.state.value}</h3>
<form onSubmit={this.handleSubmit}>
<input type="text" ref="textInput" />
<button>Submit</button>
</form>
</div>
);
}
}
El componente se inicializa y comenzamos con un valor de estado predeterminado establecido en una cadena vacía (value="’
). El componente representa el texto y el formulario, como de costumbre y, como antes, el texto H3 actualiza su estado cuando el formulario se envía con los contenidos ingresados en el campo de entrada.
Creamos una referencia estableciendo el ref
prop del campo de entrada para textInput
. Eso nos da acceso al valor de la entrada en el handleSubmit()
método usando this.refs.textInput.value
.
Reenviar una referencia de un componente a otro
** El reenvío de referencias es la técnica de pasar una referencia de un componente a un componente hijo haciendo uso de la React.forwardRef()
método.
Vea el Pen React Ref – forward Ref de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Volviendo a nuestro ejemplo de ejecución de un campo de entrada que actualiza el valor del texto cuando se envía:
class App extends React.Component {
constructor(props) {
super(props)
this.inputRef = React.createRef();
this.state = {
value: "'
}
}
handleSubmit = e => {
e.preventDefault();
this.setState({ value: this.inputRef.current.value})
};
render() {
return (
<div>
<h1>React Ref - createRef</h1>
<h3>Value: {this.state.value}</h3>
<form onSubmit={this.handleSubmit}>
<Input ref={this.inputRef} />
<button>Submit</button>
</form>
</div>
);
}
}
Hemos creado la referencia en este ejemplo con inputRef
, que queremos pasar al componente hijo como un atributo ref que podemos usar para actualizar el estado de nuestro texto.
const Input = React.forwardRef((props, ref) => (
<input type="text" ref={ref} />
));
Aquí hay una forma alternativa de hacerlo definiendo la referencia fuera del componente de la aplicación:
const Input = React.forwardRef((props, ref) => (
<input type="text" ref={ref} />
));
const inputRef = React.createRef();
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
value: ''
}
}
handleSubmit = e => {
e.preventDefault();
this.setState({ value: inputRef.current.value})
};
render() {
return (
<div>
<h1>React Ref - createRef</h1>
<h3>Value: {this.state.value}</h3>
<form onSubmit={this.handleSubmit}>
<Input ref={inputRef} />
<button>Submit</button>
</form>
</div>
);
}
}
Usando ref para la validación del formulario
Todos sabemos que la validación de formularios es muy difícil, pero algo para lo que React es adecuado. Ya sabes, cosas como asegurarse de que un formulario no se pueda enviar con un valor de entrada vacío. O requiriendo una contraseña con al menos seis caracteres. Los árbitros pueden resultar útiles para este tipo de situaciones.
Consulte el Pen React ref Pen: validación de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
class App extends React.Component {
constructor(props) {
super(props);
this.username = React.createRef();
this.password = React.createRef();
this.state = {
errors: []
};
}
handleSubmit = (event) => {
event.preventDefault();
const username = this.username.current.value;
const password = this.password.current.value;
const errors = this.handleValidation(username, password);
if (errors.length > 0) {
this.setState({ errors });
return;
}
// Submit data
};
handleValidation = (username, password) => {
const errors = [];
// Require username to have a value on submit
if (username.length === 0) {
errors.push("Username cannot be empty");
}
// Require at least six characters for the password
if (password.length < 6) {
errors.push("Password should be at least 6 characters long");
}
// If those conditions are met, then return error messaging
return errors;
};
render() {
const { errors } = this.state;
return (
<div>
<h1>React Ref Example</h1>
<form onSubmit={this.handleSubmit}>
// If requirements are not met, then display errors
{errors.map(error => <p key={error}>{error}</p>)}
<div>
<label>Username:</label>
// Input for username containing the ref
<input type="text" ref={this.username} />
</div>
<div>
<label>Password:</label>
// Input for password containing the ref
<input type="text" ref={this.password} />
</div>
<div>
<button>Submit</button>
</div>
</form>
</div>
);
}
}
Usamos el createRef()
para crear referencias para las entradas que luego pasamos como parámetros al método de validación. Poblamos el errors
array cuando cualquiera de las entradas tiene un error, que luego mostramos al usuario.
¡Eso es un ref … er, un abrigo!
Con suerte, este tutorial le dará una buena comprensión de lo poderosos que pueden ser los árbitros. Son una forma excelente de actualizar parte de un componente sin la necesidad de volver a renderizarlo por completo. Eso es conveniente para escribir código más ágil y obtener un mejor rendimiento.
Al mismo tiempo, vale la pena seguir los consejos de los propios documentos de React y evitar usar ref demasiado:
Su primera inclinación puede ser utilizar referencias para “hacer que las cosas sucedan” en su aplicación. Si este es el caso, tómese un momento y piense más críticamente acerca de dónde debería pertenecer el estado en la jerarquía de componentes. A menudo, queda claro que el lugar adecuado para “poseer” ese estado es en un nivel superior en la jerarquía.
¿Consíguelo? ¿Entendido? Bien.