@composi/runtime:

Update

Lógica de Negocios del Programa

El método update es para contener toda la lógica de negocios para el programa El método escucha los mensajes, cuando recibe uno, lo chequéa para averiguar cuál es y entonces ejecuta una acción apropiada. Por definir acciones diferentes, instruyes update cómo gestionarlas.

Update recibe tres argumentos: mensaje, estado y send. El primer argumento es el estado actual del programa. Mensaje es cualquier mensaje enviado por una interación del usuario con la vista. Send permite que envías en mensaje a otra acción. Si el programa es complejo, a lo mejore va requerir enviar varios mensajes a update. Puesto que send solo puede tratar de uno solo argumento, es conveniente combinar lo todo como un objeto literal con tipo y datos. Nota cómo hacemos eso en el escrito siguiente.

<p class='formulario'>
  <input autofocus onchange={consigueValorInput} type="text" />
  <button class='añadir-ítem' onclick={()=> send({type: 'añadir-ítem', dato: valorDeInput})}>Añadir</button>
</p>

Saber que las vista mandará un objeto con propiedad de tipo como mensaje, podemos poner una prueba en la función update para captar los mensajes por tipo. Aquí es un ejemplo sencillo. Fíjate cómo en la función update chequeamos cuál mensaje fue enviado, entonce ejecutamos la accióna apropiada, como "añadir-ítem" o "eliminar-ítem".


const programa = {
  init() {
    return estado
  },
  view(estado, send) {
    return render(<Lista {...{ estado, send }} />, section)
  },

  // La lógica de negocios se encuentra en el método update.
  // Intercepta las acciones enviadas por la vista.
  // Usar esas acciones para transformar al estado.
  // Después se devuelve el nuevo estado.
  // Eso causará que la vista se actualice.
  update(estado, mensaje, send) {
    const estadoPrevio = clone(estado)
    switch (mensaje.type) {
      case 'añadir-ítem':
        const valor = mensaje.valorDeInput
        if (valor) {
          estadoPrevio.frutas.push({ clave: estadoPrevio.newKey++, valor })
          return estadoPrevio
        } else {
          alert('¡Por favor de un valor!')
          return estado
        }
        break
      case 'eliminar-ítem':
        estadoPrevio.frutas = estadoPrevio.frutas.filter(item => item.clave != mensaje.clave)
        return estadoPrevio
        break
    }
  }
}

Aquí es el ejemplo vivo:

See the Pen @composi/core + entorno de ejecución by Robert Biggs (@rbiggs) on CodePen.

Date cuenta de que no importa qué decisión tomemos con una acción, siempre tenemos que devolver el estado. Cada acción debe devolver el estado, incluso si no realiza cambios en el estado. No hacerlo generará un error. Esto se debe a que las acciones pasan el estado a la vista para representarse, por lo que no devolver el estado hará que la vista falle porque nunca recibió el estado.

El hecho de que siempre tienes que devolver el estado, aun cuando no haya cambios, no quiere decir que esto causara que las vista vuelva a renderizarse. De echo, la función render chequéa el estado y las props del componente cuanto antes y para si son idénticos

Inmutabilidad

En el ejemplo anterior, usamos la función clone para clonar el estado. Esto nos permite manipular de forma segura el clon sin afectar el estado actual del programa. Cuando terminamos con modificaciones al clon del estado, lo devolvemos. Esto luego se pasa al método view para renderizar y se vuelve a asignar al estado del programa. clone viene preinstalado cuando creas un nuevo proyecto @composi/core. Pero necesitas importarlo en tu proyecto para usarlo:

import { h, render, run } from '@composi/core'
import { clone } from '@composi/merge-objects'
// With clone imported, you can use it to clone program state.
const program = {
  init() {
    return state
  },
  view(state, send) {
    return render(<List {...{ state, send }} />, section)
  },
  // Update now returns the actions function
  // which contains the program's business logic:
  update(state, msg, send) {
    // Create a deep clone of state:
    const prevState = clone(state)
    // Pass cloned state to actions:
    return actions(prevState, msg, send)
  }
}

Acerca de Redux

Si está familiarizado con Redux, puede observar algunas similitudes con la forma en que funcionan las acciones de update. Eso es porque Redux se inspiró en la arquitectura Elm. La diferencia está en los detalles. Los mensajes enviados por la vista se parecen a las acciones de Redux, y las acciones de update se parecen a los reducers de Redux. Son similares, pero diferentes. Los reducers de Redux se llaman así porque toman el estado, realizan cualquier número de operaciones y luego devuelven el nuevo estado. Las acciones del entorno de ejecución, por otro lado, también pueden devolver un nuevo estado, o también pueden disparar un efecto. Debido a que pueden hacer más de una cosa, no pueden llamarse reducers. Aun así, en la gran mayoría de los casos, actuarán como reducers de Redux. Ese es el caso de uso más común.

A continuación se muestra un ejemplo práctico de un programa en el que la vista envía varios mensajes diferentes para actualizar, que los examina para ver qué tipo de ellos deben realizar la acción apropiada. Examínalo detenidamente para ver cómo los mensajes agrupan los datos para enviarlos a las acciones, que luego actualizan el estado y hacen que la vista también se actualice. Hemos utilizado varios eventos del ciclo de vida en los elementos del componente funcional para manejar el enfoque del input, valor del input, etc. Utilizamos un evento onchange para obtener el valor del input para poder enviarla. en un mensaje para actualizar.

See the Pen @composi/core + entorno de ejecución by Robert Biggs (@rbiggs) on CodePen.

Enfoque Alternativo

Hay otra forma de enviar mensajes y capturarlos utilizando una unión etiquetada. @composi/core permite esto a través de su función union. Básicamente, esto crea una matriz de valores de cadena para los nombres de funciones y las acciones que se utilizarán en update. Esto puede parecer complicado, pero en realidad es bastante simple y resulta en un código más limpio y fácil de leer. Debes de leer la documentación sobre cómo utilizar Unión Etiquetada.