004. Estado Reactivo

En el capítulo anterior empezamos a implementar el concepto del estado, transformando un pequeño ejercicio de manipulación del DOM tradicional en Javascript, agregando este concepto del estado, tener un template UI y una función que renderice.

Sin embargo estamos trabajando directamente con el state (estado), y esto, en librerías o frameworks reactivos como React o Angular no está bien visto, por lo que en el ejercicio que pondremos en este capítulo vamos a hacer que el estado se actualice de manera reactiva, de hecho, si se ha trabajado con React se verán muchas coincidencias en la manera como React actualiza el estado en aplicaciones basadas en esta librería.

El detalle de hacer reactivo nuestro estado es evitar manipularlo directamente, así que lo que haremos será crear un método que nos permita manipular el state de manera reactiva.

En una programación basada en el estado es muy importante que al inicio de nuestra aplicación consideremos todas las posibles variables que justamente van a formar parte de ese estado, para que, ya sea por interacciones del usuario o por interacciones que se hagan más adelante, nuestro estado no se vea afectado por valores que no necesitemos en un principio. Por lo tanto, cada propiedad que vayamos a trabajar en el estado de nuestra aplicación la definimos al inicio, aunque no tenga valor, y gracias al método setState() evaluamos que la tenga y si la tiene la actualiza, y si no nuestro estado la está ignorando, y de esta manera protegemos la integridad del estado de nuestra aplicación. Es por ello que es importante hacer el cambio con la función setState() y no trabajar directamente en el estado.

Una de las propiedades, como dijimos en capítulos anteriores, es que el estado tiene que permanecer inmutable, es decir, que cualquier persona no lo pueda modificar, es por ello que la función setState() es la que se encarga de modificarlo.

Vamos a crear un archivo nuevo denominado 01_reactividad-estado.js.

<!DOCTYPE html>
<html lang="es">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Reactividad del Estado</title>
  </head>

  <body>
    <h1>Reactividad del Estado</h1>

    <form id="todo-form">
      <input type="text" id="todo-item" placeholder="Tarea por hacer" />
      <input type="submit" value="Agregar" />
    </form>

    <h2>Lista de tareas</h2>

    <ul id="todo-list"></ul>

    <script>
      const d = document;

      // El State
      const state = {
        todoList: [],
        nombre: "",
      };

      // Template
      const template = () => {
        if (state.todoList.length < 1) {
          return `<p><em>Lista sin tareas por hacer</em></p>`;
        }

        let todos = state.todoList.map((item) => `<li>${item}</li>`).join("");

        return todos;
      };

      // Render UI
      const render = () => {
        console.log(state);
        const $list = d.getElementById("todo-list");
        if (!$list) return;
        $list.innerHTML = template();
      };

      // Actualizar el State de manera reactiva
      const setState = (obj) => {
        for (let key in obj) {
          if (state.hasOwnProperty(key)) {
            state[key] = obj[key];
          }
        }

        render();
      };

      d.addEventListener("DOMContentLoaded", render);

      // Estableciendo valores por defecto al state
      setState({
        todoList: ["Tarea 1", "Tarea 2", "Tarea 3"],
        nombre: "Francisco",
      });

      // Estado mutable, ya que permite modificar el estado directamente creando una copia del objeto y agregando otro elemento
      const items = state.todoList;
      items.push("Tarea 10");

      d.addEventListener("submit", (e) => {
        if (!e.target.matches("#todo-form")) return false;
        e.preventDefault();

        const $item = d.getElementById("todo-item");

        if (!$item) return;

        // Actualizar el State y la UI
        state.todoList.push($item.value);
        render();

        // Limpiar el input
        $item.value = "";
        $item.focus();
      });
    </script>
  </body>
</html>
Scroll al inicio