Crea una App web de Ingresos y Egresos personales

Crea una App web de Ingresos y Egresos personales

Hola, ¿cómo estás? Espero que muy bien y con muchas ganas de aprender. Estoy de vuelta con nuevo material para ti con una aplicación web para el control de ingresos y egresos personales.

En esta guía te voy a enseñar paso a paso cómo desarrollar una app sencilla, pero funcional que te permita llevar un registro de tus finanzas personales. Veremos cómo usar diversos componentes para crear la interfaz de usuario, cómo almacenar los datos y cómo implementar algunas funcionalidades básicas como agregar y eliminar registros.

Al final del curso tendrás una app web lista para usar y podrás personalizarla a tu gusto. ¿Te animas? Entonces empecemos.

Acompáñame a crear esta aplicación de ingresos y egresos, útil y eficaz para mejorar nuestra gestión financiera, el cual puede ofrecer las siguientes características:

  • Registrar ingresos y egresos mensuales.
  • Mostrar un resumen gráfico de nuestra situación financiera, indicando el porcentaje de ingresos y egresos.
  • Visualizar un listado con el historial de las transacciones.
  • Eliminar cualquier transacción del historial.

Para crear esta aplicación de ingresos y egresos con React, tendremos la siguiente estructura, donde te explicaré a detalle el funcionamiento de cada uno de los componentes:

  1. GlobalState.jsx
  2. AppReducer.jsx
  3. App.jsx
  4. GlobalProvider
  5. Balance
  6. IncomeExpenses
  7. ExpenseChart
  8. TransactionForm
  9. TransactionList
  10. TransactionItem

1.GlobalState.jsx

Con este componente definimos un estado inicial que contiene un arreglo de transacciones, que se guardan en el almacenamiento local del navegador. Luego, creamos un contexto usando el hook createContext, que permite acceder al estado y a las funciones que lo modifican desde cualquier componente hijo.


También está presente el componente GlobalProvider, que envuelve a los componentes hijos, así obtenemos el contexto usando el hook useContext. Dentro de este componente, se usa el hook useReducer para crear un estado, que se encargará de ejecutar las acciones definidas en el archivo AppReducer.js.


Seguidamente usamos el hook useEffect para actualizar el almacenamiento local cada vez que cambia el estado. Además esta función expone dos funciones para añadir y eliminar transacciones, que envían acciones al useReducer con el tipo y la carga útil correspondientes.

Este es un ejemplo de cómo usar el Context API para compartir datos entre componentes sin tener que pasarlos como props. Con el componente Context.Provider obtenemos el valor del contexto a todos los componentes hijos que lo consumen.


En este momento, el valor del contexto es un objeto que contiene las transactions, la función para agregar y eliminar una transacción. Estas funciones son definidas en el reducer, que maneja el estado del contexto.

El {children} es una propiedad especial que representa los elementos hijos que se pasan al componente Provider. Así, cualquier componente hijo que use el hook useContext podrá acceder al valor del contexto y modificarlo con los datos de nuestras transacciones.

2. AppReducer.jsx

En este archivo creamos una función que toma el estado y la acción como argumentos y devuelve el nuevo estado según el tipo de acción. En dicha función utilizamos switch para evaluar el tipo de acción, que puede ser ADD_TRANSACTION o DELETE_TRANSACTION.


En el caso de ADD_TRANSACTION, la función devuelve un nuevo objeto con el mismo estado, pero añadiendo la action.payload al final del array de transacciones. En el caso de DELETE_TRANSACTION, la función devuelve un nuevo objeto con el mismo estado, pero filtrando el array de transacciones para eliminar la transacción con el id igual a la action.payload.

En el caso por defecto, la función nos devuelve el mismo estado sin modificarlo.

3. App.jsx

Está compuesto de varios componentes que se importan desde otros archivos. Estos componentes son:


a. GlobalProvider: provee el contexto global que contiene la información sobre las transacciones del usuario y las funciones para agregar y eliminar las transacciones.

b. Balance: muestra el balance total, es decir, la diferencia entre los ingresos y egresos.

Dentro de esta función, usamos el hook useGlobalState para acceder al estado global de las transacciones, que es un arreglo de objetos con propiedades amount y text.


Después, la variable llamada amounts mapea el arreglo de transacciones y extrae solo los valores de amount. Luego, crea otra variable llamada total que suma todos los valores de amounts usando el método reduce y los formatea con dos decimales.

Finalmente, la función Balance se exporta como un módulo para ser usada en el componente App.jsx.

c. IncomeExpenses: expone el total de ingresos y egresos, así como el porcentaje que representa cada uno sobre el balance total.

A continuación, importamos el hook useGlobalState que permite acceder al estado global de la aplicación. Enseguida, realizamos una función IncomeExpenses, en donde calculamos los ingresos, con el método map para obtener un arreglo con los montos de cada transacción.

Inmediatamente, aplicamos el método filter para conseguir solo los montos positivos, que representan los ingresos. Por otro lado, disponemos del método reduce para sumar todos los montos y recibir el total de ingresos. Finalmente, el resultado se redondea a dos decimales con el método toFixed.

Seguimos con el cálculo de los egresos, tomamos el mismo código anterior, pero con los montos negativos, que representan los egresos. Además, multiplicamos el resultado por -1 para obtener un valor positivo. Así podemos comparar fácilmente los ingresos y egresos, por ser transacciones con un monto positivo.

d. ExpenseChart demuestra un gráfico circular con la distribución de los ingresos y egresos.


Iniciamos, con la instalación de VictoryPie, bajo el comando npm install victory, además importamos VictoryPie y VictoryLabel de la librería victory, para crear el gráfico. Esta plataforma fue creada para ofrecer una solución de visualización de datos basada en React Native.

VictoryPie es una librería de gráficos circulares que permite personalizar el tamaño, el color, el ángulo y el estilo de las porciones. También se puede añadir animación, eventos y etiquetas a los gráficos. Esta plataforma es de código abierto y se puede usar tanto en aplicaciones web como móviles.

También importamos el hook useGlobalState, que es el que provee el estado global de la aplicación.

Luego, construimos la función llamada ExpenseChart, que es el componente principal. Dentro de esta función, están las transacciones del estado global usando la desestructuración.

A partir de las transacciones, calculamos el total de ingresos y el total de egresos, usando el método filter para seleccionar solo las transacciones positivas o negativas, y el método reduce para sumar sus cantidades.

También calculamos el porcentaje de egresos sobre los ingresos, usando la fórmula (totalExpenses / totalIncome) * 100, y se redondea con la función Math.round. El porcentaje de ingresos se obtiene restando el porcentaje de egresos a 100.

Después de todo, retorna un elemento VictoryPie, que recibe las siguientes propiedades:

  • colorScale con un arreglo con los colores que se usarán para el gráfico.
  • data otro arreglo con los objetos que representan los datos del gráfico, cada uno con una etiqueta (x) y un valor (y).
  • animate un objeto con la duración de la animación del gráfico
  • labels una función que devuelve el texto que se mostrará para cada dato, en este caso el porcentaje.
  • labelComponent es un elemento VictoryLabel que recibe el ángulo y el color del texto.

e. TransactionForm: permite ingresar una nueva transacción, especificando el monto, el tipo (ingreso o egreso). Además usamos el hook useGlobalState para acceder a la función addTransaction que se encarga de actualizar el estado global con la nueva transacción.

En este componente definimos una función onSubmit que se ejecuta cuando enviamos los datos del formulario. Adicionalmente previene el comportamiento por defecto del evento, genera un identificador único para la transacción usando window.crypto.randomUUID y llama a addTransaction con un objeto que contiene el identificador, la descripción y la cantidad (convertida a número con el operador +).

Asimismo nos devuelve un elemento <div> que contiene un formulario con dos campos de entrada (uno de tipo texto para la descripción y otro de tipo número para el monto) y un botón para enviar el formulario.

Los campos de entrada tienen un atributo onChange que asigna el valor introducido por nosotros a las variables de estado description y amount, respectivamente.


f. TransactionList: contiene la lista de todas las transacciones y cada transacción tiene un botón para eliminarla. Este componente usa el hook personalizado llamado useGlobalState para acceder al estado global de la aplicación, que contiene un array de transacciones.

Luego, se debe envolver el componente TransactionList dentro del proveedor del contexto GlobalState, que recibe como prop el estado inicial de las transacciones.

Para cada transacción en el array, el componente renderiza otro componente llamado TransactionItem, que recibe la transacción y su id como props. Este componente se encarga de mostrar los detalles de cada transacción, como el monto y el tipo.

g. TransactionItem: se recibe una transacción como propiedad. En la cual muestra la descripción y el monto de la transacción en una lista, con un botón para eliminarla.


Usamos el hook useGlobalState para acceder a la función deleteTransaction del contexto global, que se encarga de borrar la transacción del estado. De la misma manera este componente también usa el icono FaTrashCan de la librería react-icons para mostrar el botón de eliminar.


Espero que este artículo te haya sido útil para aprender cómo crear una aplicación web de ingresos y egresos con React. Esta es una herramienta muy poderosa y versátil para desarrollar interfaces de usuario dinámicas y modernas. Te invito a que sigas practicando y explorando las posibilidades que te ofrece React.

Gracias por leer y hasta la próxima.

💡
Las opiniones y comentarios emitidos en este artículo son propiedad única de su autor y no necesariamente representan el punto de vista de Listopro.

Listopro Community da la bienvenida a todas las razas, etnias, nacionalidades, credos, géneros, orientaciones, puntos de vista e ideologías, siempre y cuando promuevan la diversidad, la equidad, la inclusión y el crecimiento profesional de los profesionales en tecnología.