Para poder realizar este taller ud debe:
En el tutorial pasado presentamos el primer acercamiento al manejo de estado en React. Usted realizó unos cambios en un programa base que le permitieron llevar la cuenta de la cantidad de clicks que se habían realizado sobre un botón. En este tutorial veremos otras capacidades con las que cuenta el manejo de estados en React.
Retomemos este tema desde el principio ... ¿Qué significa manejar el estado de un componente?
El estado de un componente está relacionado a la "memoria" que un componente puede tener de las interacciones que ha tenido con el usuario, por ejemplo, los valores que tienen los campos de texto de un formulario, ó el índice de la última opción seleccionada en un campo de selección múltiple. Esta "memoria" es la que nos va permitir "REACTionar" a las diferentes interacciones de los usuarios. Por ejemplo, si tenemos un formulario en nuestra aplicación, haciendo uso del estado actual del formulario, puedo habilitar o deshabilitar el botón de enviar, de esta forma me encargo de garantizar que se cumpla la heurística de Nielsen relacionada a la prevención de errores.
Las siguientes secciones de este codelab presentaran diferentes ejemplos y capacidades que se pueden habilitar al hacer uso de useState.
Como se presentó en el tutorial pasado, el estado se define mediante el uso de la función o hook useState
. Esta función recibe como parámetro el valor inicial del estado y retorna 1 arreglo que contiene: la variable que representa el valor actual del estado y la función a utilizar para actualizar el estado.
const [stateVariable, setStateVariable] = useState(initialState);
...
La función set
genera un re-renderizado de la interfaz cuando se termina de ejecutar el bloque de código actual, esto significa que el valor que almacenamos en la variable solo va a ser actualizado cuando se termine de ejecutar el método donde se hace el llamado a la función set
. Para esto vamos a hacer un pequeño ejemplo, diríjase a la clase "Post.js" de su aplicación, en la línea inmediatamente siguiente al llamado de setLikes
dentro del método handleLikes
imprima el valor de likes en consola. ¿Qué valor se imprime?
Para poder ver esto su método handleLikes se debería ver de la siguiente forma:
const handleLikes = () => {
console.log("Button clicked...");
setLikes(likes + 1);
console.log(likes);
};
Como podrá ver en la consola, se imprime el valor antes de su actualización. Es por esto que sabemos que una vez se termine la ejecución del método handleLikes
se realizará un re-renderizado de la página.
Ahora, vamos a hacer algunos cambios en la página para ver el manejo de estado de dos variables al mismo tiempo. Empezaremos modificando el archivo "Post.js" para que en el return del componente contemos con una campo de texto adicional, para esto agregaremos la siguiente línea de código que nos ayudará a renderizar un campo de texto dentro de los cards.
...
<input value="Hola"/>
...
Ubicamos esta línea antes de la creación del botón de "likes", su código deberá verse de la siguiente forma:
return (
<Col>
<Card style={{ width: "18rem" }}>
<Card.Body className="mb-3">
<Card.Title>{props.author}</Card.Title>
<Card.Text>{props.content}</Card.Text>
<Card.Text>{renderLikes()}</Card.Text>
<input value="Hola" />
<Button variant="primary" onClick={handleLikes}>
Like
</Button>
</Card.Body>
</Card>
</Col>
);
Una vez haya realizado este cambio su interfaz se habrá modificado y se debería ver de la siguiente forma:
Ahora crearemos el estado que maneja los cambios en el input. Para esto agregaremos un nuevo llamado al método useState
pero esta vez orientado al valor que está dentro del input. Agregaremos la siguiente línea justo debajo de la definición del estado asociado a la variable likes
.
...
const [inputText, setInputText] = useState("Hola");
...
Ahora contamos con el estado que nos ayudará a manejar los cambios en el valor del input, de esta forma podremos crear el método que se encargue de reaccionar cada vez que el usuario haga alguna modificación al texto. Para esto crearemos el método handleChange
que será invocado cuando haya un cambio en el input. Invitamos a los lectores de este codelab a intentar escribir primero su versión del método antes de continuar, así podrá comparar con la implementación recomendada.
¿Listo? Antes de continuar garanticemos que estamos en la misma página. Su método handleChange deberá lucir similar a la siguiente implementación
...
function handleChange(e) {
setInputText(e.target.value);
}
...
¿Logró obtener un resultado similar? ¿Por qué cree que usamos e.target.value
? Dado que estamos trabajando con un input, el evento que se llama cada vez que se hace un cambio en el valor es onChange
, esto quiere decir que cada vez que usted agrega una letra o un número al campo de texto se hace un llamado a este método dado que se generó un cambio en el campo de texto. Por lo tanto, la forma correcta de obtener el valor del campo de texto es mediante la expresión e.target.value
.
Estamos acercándonos a completar el manejo del estado del campo de texto que agregamos, ¿Qué nos hace falta? Primero, debemos asociar el método handleChange
con el campo de texto y segundo, hacer uso del valor almacenado en la variable inputText
. Empezaremos modificando la declaración del campo de texto para que cada que reconozca un cambio actualice el estado. Para esto agregaremos el atributo onChange
al elemento input y le asignaremos el llamado al método handleChange. Su código deberá lucir de la siguiente forma:
...
<input value="Hola" onChange={handleChange}/>
...
Estamos a un paso de terminar, lo único que nos hace falta es hacer uso del valor actual del estado que hemos construido, para esto modificaremos el atributo value del campo de texto. Para esto reemplazamos "Hola" por {inputText}, para que el campo de texto cada vez que se modifique muestre el último valor almacenado.
Al finalizar esta sección su código se debe ver de la siguiente forma:
import Button from "react-bootstrap/Button";
import Card from "react-bootstrap/Card";
import Col from "react-bootstrap/Col";
import { useState } from "react";
function Post(props) {
const [likes, setLikes] = useState(props.likes)
const [inputText, setInputText] = useState("Hola");
function handleChange(e) {
setInputText(e.target.value);
}
const renderLikes = () => {
if (likes === 0) return "Give us a like";
else return "Likes: " + likes;
};
const handleLikes = () => {
console.log("Button clicked...");
setLikes(likes+1);
console.log(likes)
};
return (
<Col>
<Card style={{ width: "18rem" }}>
<Card.Body className="mb-3">
<Card.Title>{props.author}</Card.Title>
<Card.Text>{props.content}</Card.Text>
<input value={inputText} onChange={handleChange}/>
<Card.Text>{renderLikes()}</Card.Text>
<Button variant="primary" onClick={handleLikes}>Like</Button>
</Card.Body>
</Card>
</Col>
);
}
export default Post;