Skip to main content

· 4 min read
Lucas Fernández Aragón

En este post introducimos el concepto de reglas para asistentes de IA generativa ("Copilot Rules", "Cursor Rules") como un mecanismo ligero de alineación: documentos cortos que definen estilo, límites, convenciones y prioridades para que las sugerencias y acciones de un agente / modelo se ajusten a nuestra arquitectura y estándares.

Objetivo: Reducir re-trabajo y divergencias estableciendo expectativas explícitas para la IA antes de generar o refactorizar código.

¿Por qué Definir Reglas?

Problema ObservadoSíntomaRegla Mitiga
Sugerencias inconsistentes de estilosClases utilitarias mezcladas con estilos inlineRegla unifica Tailwind + shadcn
Código sin testsPR sin cobertura mínimaRegla exige pruebas unitarias/edge
Lógica duplicadaHooks replicadosRegla obliga a reutilizar helpers existentes
Descripciones PR pobresContexto insuficienteRegla estructura plantillas descriptivas

Beneficios: menor tiempo de revisión, uniformidad arquitectónica, onboarding acelerado y trazabilidad de decisiones.

Anatomía de una Buena Regla

  1. Contexto (1–2 líneas) — ¿qué escenario cubre?
  2. Directiva concreta (imperativo) — "Usa X / Evita Y".
  3. Justificación breve — por qué importa (rendimiento, DX, seguridad).
  4. Ejemplo antes/después (cuando aplica).
  5. Criterio de verificación (cómo comprobar cumplimiento).

Mantener cada regla atómica: si una directiva requiere excepciones complejas, dividirla.

Archivos y Ubicación

HerramientaArchivo sugeridoPropósito
GitHub Copilot (Chat / Agent)docs/ai/copilot-rules.mdAlinear generación y PRs agentes
Copilot Custom InstructionsInterfaz web (campo organización/usuario)Persistir estilo global respuestas
Cursor.cursor/rules (o cursor/rules.md)Controlar refactors y planes multi‑archivo
Repos multi-equipodocs/ai/shared-rules.mdNúcleo común (evitar duplicación)

Estructura mínima recomendada de copilot-rules.md:

# Copilot Rules

## Estilos
Usa exclusivamente Tailwind + componentes shadcn; prohíbe styled-components.

## Tests
Toda nueva función pública requiere test (happy + error). Si es hook: probar estados loading/error.

## Arquitectura
Preferir extracción a hooks/utilities antes de duplicar lógica > 2 líneas repetidas.

## PRs
Incluir sección "Contexto" + "Cambios" + "Riesgos" + "Tests".

Ejemplos de Reglas Concretas

1. Estilos (Tailwind + shadcn)

Regla: Usa clases utilitarias y componentes generados con npx shadcn add evitando duplicar estilos en archivos sueltos.

Justificación: Consistencia visual y menor CSS muerto.

Anti‑patrón:

<div style={{ marginTop: 12, color: '#333' }}>Hola</div>

Correcto:

<div className="mt-3 text-foreground">Hola</div>

2. Hooks Reutilizables

Regla: Extrae efectos compartidos a un hook cuando se repita el mismo useEffect en ≥ 2 componentes.

Verificación: Buscar patrón por regex antes de introducir segundo duplicado.

3. Autenticación

Regla: Toda lógica nueva que necesite usuario autenticado debe consumir useAuth() y nunca acceder directo a localStorage.

Justificación: Encapsular persistencia y reducir fugas.

4. Testing

Regla: Añade test Vitest para cualquier rama condicional nueva (if/else, early return).

Criterio: Revisar diff: cada if ( agregado implica test nuevo o ampliado.

5. Estructura de Commits / PR

Regla: Commits atómicos: scaffold, feature, refactor, tests, docs.

Plantilla PR:

## Contexto
Motivación breve.

## Cambios
- Lista clara

## Riesgos
- Riesgos y mitigaciones

## Tests
- Casos añadidos

Ejemplo de Archivo .cursor/rules

RULE: Prefer tailwind utility classes over inline styles.
WHY: Ensures consistency and leverages design tokens.
CHECK: No `style={` unless dynamic calc; else refactor.

RULE: For new hooks include JSDoc with params + return description.
WHY: Mejora DX y autocompletado.
CHECK: grep `use[A-Z].+\nexport` then verify preceding comment.

RULE: When adding a context provider update providers tree in main.tsx.
WHY: Evita fallos en componentes consumidores.
CHECK: Diff must show main.tsx change if new context file added.

Integración en Flujos Copilot Agent

  1. Issue incluye enlace a reglas.
  2. Primer mensaje al agente: "Respeta docs/ai/copilot-rules.md".
  3. Tras PR generado, solicitar resumen justificación de cualquier desviación.

Métricas de Efectividad

MétricaCómo MedirMeta
Violaciones detectadas por revisiónConteo manual semanalTendencia ↓
Cobertura en PRs generados por agente% PR con sección completa> 95%
Duplicación lógica (ej: hooks)Sonar/grep heurístico< baseline

Buenas Prácticas de Mantenimiento

  • Revisar reglas trimestralmente (evitar obsolescencia).
  • Marcar reglas experimentales con prefijo EXP:.
  • Archivar reglas deprecadas en sección changelog dentro del mismo archivo.

Checklist de Adopción

[ ] Archivo copilot-rules.md creado
[ ] Archivo .cursor/rules creado
[ ] Referencia añadida a README
[ ] Issues plantilla enlazan reglas
[ ] Métricas tracking definidas

Conclusión

Definir un set pequeño y evolutivo de reglas crea una capa de alineación que transforma la IA de asistente genérico a par programador contextualizado. Mantén las reglas vivas: si una no aporta valor medible, se simplifica o elimina.

· 7 min read
Lucas Fernández Aragón

Progressive Web Apps

Las Progressive Web Apps (PWA) representan una evolución natural de las aplicaciones web tradicionales, combinando lo mejor de las aplicaciones web y las aplicaciones móviles nativas. En este artículo exploraremos qué son las PWA, sus beneficios, las tecnologías que las hacen posibles y, especialmente, cómo se han implementado en este mismo proyecto de documentación.

· 8 min read
Lucas Fernández Aragón

First steps with redux

Hoy vamos a explicar los conceptos más básicos de Redux y React Redux de la forma más concisa posible, primero explicando los conceptos más importantes y luego viendo su implementación tanto en TypeScript "vanilla" como en React.

Redux

Redux es una biblioteca muy popular de JavaScript que permite manejar el estado de una aplicación. El estado de aplicación es un objeto global que maneja información heterogénea usada por al aplicación, por poner un ejemplo, el estado para controlar la visibilidad de un spinner si estamos cargando datos en nuestra aplicación.

Otro de los grandes objetivos del control de estado es pasar información entre componentes sin caer en el prop drilling o el tener que pasar un mismo valor entre múltiples componentes padre-hijos para completar la cadena.

Para todo esto necesitamos bibliotecas de manejo de estados como Redux. Redux como biblioteca es muy popular porque basa su uso en unos principios muy sencillos e intuitivos, fundamentados en los siguientes patrones:

  • Single Source Of Truth: O "única fuente de veracidad", que básicamente significa que solo tenemos un lugar (llamado Store) donde vamos a guardar el estado de toda la aplicación.
  • Inmutabilidad: En Redux no vamos a cambiar el estado de un objeto y sus propiedades directamente, si no que vamos a crear un nuevo objeto calculando el nuevo estado de la aplicación y así actualizándolo con el nuevo objeto creado.

Componentes

Componentes Redux

Con estos principios, vamos a ver los componentes esenciales de Redux:

Store

El Store o almacenamiento contiene el estado de la aplicación. Este Store es un objeto con sus funciones y atributos al que podemos suscribirnos para escuchar eventos cuando el objeto Store se actualiza. Este objeto es referenciado muchas veces como el "árbol de estado", ya que es posible almacenar cualquier valor y anidar tanta información como se necesite.

Actions

Son objetos JavaScript que describen qué a pasado en un estado, pero no como este estado debe cambiar. Simplemente mandamos (dispatch) estas acciones a nuestro objeto Store siempre que queramos actualizar el estado. La gestión del cambio será efectuada por los Reducers.

Estas acciones son objetos que tienen al menos un atributo, en este caso por convenio es type, para indicar la acción, y luego el resto de atributos necesarios para indicar la acción.

Reducers

Los Reducers son funciones puras que definen como debe cambiar el estado de la aplicación. Cuando enviamos (dispatch) una Action a nuestro Store, la acción pasa a un Reducer que la interpretará para modificar el estado.

Una función reducer toma dos parámetros, el estado previo y la acción que vamos a enviar y devuelve un nuevo estado.

let reducer = (previousState, action) => newState

Básicamente un reducer computará el nuevo estado de la aplicación basándose en el estado (y su tipo) que vamos a enviar. Lo más normal es que a medida que una codebase se vuelve más compleja, los reducers aumentarán en funcionalidad y complejidad, es por ello que la mejor estrategia a seguir es dividirlos en múltiples partes y luego combinarlos con la función combineReducers.

Flujo

Flujo Redux

El flujo de la aplicación es relativamente sencillo conociendo los componentes, solo tenemos que utilizar en conjunto los elementos antes mencionados:

  1. Lo primero tendremos que suscribirnos al Store y tener un mecanismo para reaccionar.
  2. Ahora en cualquier cambio de estado que queramos hacer, solo tenemos que llamar al método store.dispatch() con la Action que queramos realizar.
  3. Redux gestiona esta acción mediante el Reducer.
  4. Al estar suscritos al Store, nos devolverá el nuevo estado que podremos añadir a nuestra aplicación.

Como veis, incorporar Redux en nuestra aplicación es relativamente sencillo una vez tenemos todos los conceptos claros. Ahora vamos a ver unos ejemplos prácticos para TypeScript y React.

Redux + TypeScript

Aplicación en TypeScript

Vamos a hacer primero una versión en TypeScript vanilla para asentar los conceptos de forma correcta. Esta aplicación consta de un formulario sencillo con el que añadir recordatorios. Cada vez que pulsemos el botón "Add", mandaremos una acción a Redux con el recordatorio que queremos crear.

Primero vamos a definir una interfaz para los reminders, que constará de un atributo title para el título y description para la descripción.

interface Reminder {
title: string;
description: string;
}

Ahora vamos a crear nuestra Action. De momento solo vamos a crear un acción para añadir nuevos recordatorios a nuestro estado global, es por ello que primero definiremos la interface de nuestra acción, seguido del atributo type que controlaremos en nuestro reducer y atributos adicionales como son title y description que servirán para crear el recordatorio.

// ----------- Action ------------
interface ReminderAction {
type: string;
title: string;
description: string;
}

export const ADD_REMINDER: string = 'ADD_REMINDER';

export function addReminder(title: string, description: string): ReminderAction {
return { type: ADD_REMINDER, title: title, description: description };
}

Ahora generaremos nuestro reducer. Como es el primero de todos será nuestro rootReducer, en el que controlaremos todas las acciones con un switch (en este caso solo tenemos una inicialmente), en la que con un spread operator añadiremos un nuevo objeto Reminder en el array de estados de la aplicación.

// ----------- Reducer ------------ 
interface ReminderState {
reminders: Reminder[];
}
const initialState: ReminderState = {
reminders: []
};

const rootReducer = (state: ReminderState = initialState, action: ReminderAction): ReminderState => {
switch(action.type) {
case ADD_REMINDER:
return {
reminders: [
...state.reminders,
{
title: action.title,
description: action.description,
},
],
};

default:
return state;
}
}

Ya solo nos falta crear nuestra store y añadir nuestro rootReducer para tener Redux configurado en nuestra aplicación.

// ----------- Store ------------ 
const store = createStore(rootReducer);

Para la UI, lo más destacable es que vamos a tener una función llamada renderReminders que básicamente recoge el estado de nuestro Store y modifica el DOM de la aplicación para mostrar todos los recordatorios que tengamos guardados. Para que nuestra aplicación reaccione a los cambios vamos a suscribirnos al Store mediante el método store.subscribe(() => {}) al que le pasaremos nuestra función para renderizar los recordatorios.

// ----------- UI ------------
let button = document.getElementById("addButton");
let remindersDashboard = document.getElementById("reminder-dashboard");

button.onclick = function (event) {
const title = document.getElementById("titleInput").value;
const description = document.getElementById("descriptionInput").value;
store.dispatch(addReminder(title, description));
};

const renderReminders = () => {
const reminderState = store.getState().reminders;

let reminderDom = ``;

reminderState.forEach((element) => {
reminderDom += `
<div class="reminder-card">
<p class="reminder-title">${element.title}</p>
<p class="reminder-description">${element.description}</p>
</div>
`;
});

remindersDashboard.innerHTML = reminderDom;
};

store.subscribe(() => {
renderReminders();
});

https://codepen.io/lucferbux/pen/eYVWaKP

Redux + React

React App

Ahora vamos a reutilizar la mayor parte de la estructura del proyecto anterior, ya que las declaraciones de las Actions, Reducers y Store son las mismas. Nuestro objetivo ahora es conectarnos y acceder a nuestro Store a través de los componentes funcionales de nuestra aplicación. Para ello vamos a hacer uso de la librería react-redux y de varios hooks que nos facilitarán el trabajo.

Lo primero que vamos a tener que hacer es rodear nuestro componente de aplicación con el Provider de Redux, al que le pasaremos el objeto store que hemos declarado previamente. Con ello ya podremos acceder al Store global desde cualquiera de los componentes de nuestra aplicación.

ReactDOM.render(
<Provider store={store}>
<App />
</Provider>, document.querySelector(".container"));

Vamos a hablar primero de useSelector. Este hook permite devolver una parte del objeto Store a nuestro componente. El selector va a hacer una comprobación del estado anterior, y si no es el mismo, el componente accionará un renderizado. Este hook acepta un segundo parámetro que permite modificar la estrategia de comparación entre estados, en este caso usaremos shallowEqual para que no renderice el componente si en el cambio de estado los valores permanecen igual.

const RemindersComponent = () => {
const reminders = useSelector((state) => state.reminders, shallowEqual);

return (
<div class="reminders-dashboard">
{ reminders.map((reminder, index) => (
<div className="reminder-card">
<p className="reminder-title">{reminder.title}</p>
<p className="reminder-description">{reminder.description}</p>
</div>

))}
</>
);
};

Por otro lado tenemos useDispatch(), que nos permitirá mandar una acción a nuestro Store para que lo procese el reducer. Es tan fácil como llamar a la función y pasar la Action que ya teníamos generada.

const App = () => {
const [title, setTitle] = useState("");
const [description, setDescription] = useState("");
const dispatch = useDispatch();

const dispatchReminder = () {
dispatch(addReminder(title, description));
}

return (
<div className="wrapper">
<HeaderComponent title={"Redux + React"} />
<FormComponent setTitle={setTitle} title={title} setDescription={setDescription} description={description} submitForm={dispatchReminder}/>
<RemindersComponent />
</div>

);
}

Con esto ya tendríamos configurado Redux en nuestro proyecto React. Como veis una vez dominamos los conceptos esenciales la implementación es relativamente sencilla. Abajo tenemos un codepen con el ejemplo mencionado antes.

https://codepen.io/lucferbux/pen/XWZRQwZ

Saludos 👋

· 3 min read
Lucas Fernández Aragón

Cloud Alternatives

En este post vamos a explicar algunas buenas prácticas que podemos aplicar en React. Estas buenas prácticas son recomendaciones que nos ayudarán a tener un código más limpio, más legible y más fácil de mantener. Vamos a dividir el post en dos secciones. La primera sección será sobre los principios SOLID y la segunda sobre buenas prácticas en React. Así tendremos una parte más focalizada a principios y otra más a checklist the buenas prácticas que podemos tener en mente.

Despliegue frontal

En la sección Cloud hemos visto como desplegar nuestro frontend con Netlify. Ahora vamos a mencionar algunas alternativas con funcionalidad similar.

  • Render: Ya hemos mencionado render en base de datos, pero también se puede usar para el despliegue de nuestra aplicación en React. Es una buena alternativa para centralizar todos los despliegues.
  • Vercel: Vercel es la plataforma de despliegue de aplicaciones web por defecto para Nextjs. Vercel es una herramienta muy completa y el sitio por defecto para funcionalidades como Server Side Rendering, Static Site Generation, etc.
  • Cloudflare Pages: Cloudflare Pages es una plataforma de despliegue de aplicaciones web que cuenta con todo el ecosistema de Cloudflare, es una alternativa muy interesante para contar con despliegues con muy poca latencia.

Despliegue backend

Como ya sabréis, para nuestro backend hemos hecho uso de Render, pero existen otras alternativas que podemos utilizar que cuentan con funcionalidades similares. Algunas de estas alternativas son:

  • Heroku: Heroku es una plataforma de despliegue de aplicaciones web, hasta hace muy poco el portal de referencia, pero que ha ido perdiendo tracción desde que eliminaron los planes gratuitos. Aún así, es una plataforma muy completa y con una gran comunidad detrás.
  • Railway: Una de las alternativas más interesantes y potentes, tiene una interfaz muy cuidada y un equipo impresionante por detrás.

Despliegue de la base de datos

Además de Atlass, existen otras alternativas para el despliegue de nuestra base de datos en la nube.

  • Render: Como ya hemos comentado, podemos hacer uso de la funcionalidad de bases de datos para desplegar nuestros datos.
  • Railway: Al igual que render, contamos con la funcionalidad de bases de datos para desplegar nuestros datos.

Por otro lado podremos cambiar la conexión y la lógica de nuestra app si hacemos uso de otros cloud providers como Google Cloud, AWS, Azure, Openshift, etc.

Alternativas BaaS (Backend As A Service)

Ya hemos visto como desplegar nuestro servicio con Firebase, pero existen otras alternativas que podemos utilizar para añadir funcionalidad cloud de forma muy sencilla a nuestro proyecto. Algunas de estas alternativas son:

  • AWS Amplify: Amplify es un conjunto de herramientas y servicios que nos permiten añadir funcionalidad cloud a nuestras aplicaciones. Amplify nos permite añadir autenticación, bases de datos, almacenamiento, API, etc. Amplify es una herramienta muy completa y con una gran comunidad detrás. Amplify es una herramienta de Amazon, por lo que si ya tenemos una cuenta de AWS, podemos utilizarla sin necesidad de crear una nueva cuenta.
  • Supabase: Supabase es una alternativa a Firebase Open Source. Supabase nos permite añadir funcionalidad cloud a nuestras aplicaciones de forma sencilla. Supabase nos permite añadir autenticación, bases de datos, almacenamiento, API, etc. Supabase es una herramienta muy completa y con una gran comunidad detrás. Supabase es una herramienta Open Source, por lo que podemos utilizarla sin necesidad de crear una cuenta.
  • Pocketbase: Al igual que Supabase, es una alternativa Open Source, está escrita en golang y permite de forma muy sencilla desplegar funcionalidades similares a los competidores en cualquier cloud.

· 6 min read
Lucas Fernández Aragón

Best Practices Header

En este post vamos a explicar algunas buenas prácticas que podemos aplicar en React. Estas buenas prácticas son recomendaciones que nos ayudarán a tener un código más limpio, más legible y más fácil de mantener. Vamos a dividir el post en dos secciones. La primera sección será sobre los principios SOLID y la segunda sobre buenas prácticas en React. Así tendremos una parte más focalizada a principios y otra más a checklist the buenas prácticas que podemos tener en mente.

Principios SOLID

En el mundo del desarrollo de software, siempre buscamos seguir buenas prácticas y principios para crear aplicaciones escalables, mantenibles y robustas. Uno de los conjuntos de principios más conocidos y ampliamente adoptados es SOLID, propuesto por Robert C. Martin. Estos principios ayudan a los desarrolladores a diseñar código de alta calidad y fácil de mantener. En este artículo, exploraremos cómo aplicar los principios SOLID en el contexto de React y proporcionaremos ejemplos de cómo aplicarlos en componentes funcionales tipados.

Principio de Responsabilidad Única (SRP)

Un componente debe tener una única responsabilidad y propósito. Al utilizar componentes funcionales y TypeScript, podemos lograr fácilmente este principio.

// Antes: Un componente que maneja la entrada de texto y la validación
const InputWithValidation: React.FC = () => {
/* código de validación y renderizado */
}

// Después: Separar en dos componentes
const TextInput: React.FC = () => {
/* solo renderizado de entrada de texto */
}

const InputValidation: React.FC = () => {
/* solo validación */
}

Principio de abierto / cerrado (OCP)

Los componentes deben estar abiertos para extenderse pero cerrados para modificarse. Esto significa que no debe ser necesario modificar un componente existente para extenderlo. En su lugar, podemos crear un nuevo componente que extienda el comportamiento del componente existente.

// Antes: Un componente cerrado para modificación
// Button.tsx
import React from 'react';

interface ButtonProps {
onClick: () => void;
label: string;
}

const Button: React.FC<ButtonProps> = ({ onClick, label }) => {
return (
<button onClick={onClick}>
{label}
</button>
);
};

export default Button;

// Después: Un componente abierto para extensión
import React from 'react';
import Button from './Button';

interface IconButtonProps extends ButtonProps {
icon: string;
}

const IconButton: React.FC<IconButtonProps> = ({ onClick, label, icon }) => {
return (
<Button onClick={onClick} label={label}>
<span className="icon">{icon}</span>
</Button>
);
};

export default IconButton;

Principio de sustitución de Liskov (LSP)

Los componentes deben poder ser reemplazados por sus subtipos sin alterar el comportamiento del programa. Esto significa que los componentes deben ser intercambiables con sus subtipos sin afectar el comportamiento de la aplicación. En el caso de componentes funcionales y TypeScript, podemos lograr esto utilizando la composición en lugar de la herencia.

// Componente base
interface ButtonProps {
className?: string;
}

const Button: React.FC<ButtonProps> = (props) => {
/* código del componente base */
}

// Componente derivado
const IconButton: React.FC<ButtonProps> = (props) => {
return <Button {...props} />;
}

Principio de segregación de interfaz (ISP)

Una entidad no debe verse obligada a depender de interfaces que no utiliza. En React y TypeScript, esto se traduce en no pasar props innecesarias a los componentes.

// Antes: Pasar props innecesarias
interface Person {
name: string;
age: number;
address: string;
}

interface PersonComponentProps {
person: Person;
}

function PersonComponent(props: PersonComponentProps) {
return (
<div>
<div>{props.person.name}</div>
<div>{props.person.age}</div>
</div>
);
}

// Después: Pasar solo las props necesarias
interface PersonComponentProps {
name: string;
age: number;
}

function PersonComponent(props: PersonComponentProps) {
return (
<div>
<div>{props.name}</div>
<div>{props.age}</div>
</div>
);
}

Principio de inversión de dependencia (DIP)

Los componentes de alto nivel no deben depender de los componentes de bajo nivel. Ambos deben depender de abstracciones. En React y TypeScript, esto significa que los componentes de alto nivel no deben depender de los componentes de bajo nivel. En su lugar, ambos deben depender de abstracciones como interfaces o tipos.

// Antes: Componente de alto nivel depende de componente de bajo nivel
import api from '~/common/api'

const DashboardComponent = () => {
const [data, setData] = useState([]);

useEffect(() => {
api.get('/dashboard').then((response) => {
setData(response.data);
});
}, []);

return (
<div>
{data.map((item) => (
<div>{item.name}</div>
))}
</div>
);
}

// Después: Ambos componentes dependen de una abstracción
const DashboardComponent = () => {
const { data, isLoading, error } = useFetchData(apiClient.getDashboardInfo);

if (isLoading) {
return <div>Loading...</div>;
}

if (error) {
return <div>Error: {error.message}</div>;
}

return (
<div>
{data.map((item) => (
<div>{item.name}</div>
))}
</div>
);
}

Buenas prácticas en React

Esta lista está conformada con elementos que usamos en nuestro equipo de desarrollo y que nos han ayudado a tener un código más limpio y fácil de mantener. No es una lista exhaustiva, pero espero que os sirva para mejorar la calidad de viestro código.

  • Verificar las declaraciones para ignorar de eslint: A veces queremos estas declaraciones (por ejemplo, para logs en consola intencionales), pero lo más probable es que estemos saltándono una buena práctica.

    • No ignorar los errores de dependencia de los React hooks.

    • No hacer uso del tip `any`` sin una muy buena razón (debe estar comentado encima de la declaración de ignorar).

  • Verificar las siguientes peculiaridades de React y TypeScript:.

    • as es una palabra clave problemática: esto probablemente signifique que estás violando la asistencia de TypeScript y, por lo tanto, probablemente tienes otro error en tus tipos que estás encubriendo.

    • Los valores de encadenamiento opcional (optional chaining) tienen valores de respaldo.

    • ¿Se ha considerado EitherNotBoth / EitherOrNone cuando las propiedades del objeto/componente están en conflicto?

    • Las propiedades de tipo opcional son opcionales porque son verdaderamente opcionales (se pueden pasar opcionalmente / tienen un buen valor de respaldo), y no porque sea más fácil para los tipos (para evitar un error de tipo).

    • Los componentes se dividen correctamente en esfuerzos bien definidos con un solo objetivo.

    • Los componentes utilizan ampliamente hooks personalizados para almacenar datos y lógica que están fuertemente acoplados.

    • Los componentes evitan el uso de useMemo para procesos que no son computacionalmente costosos.

    • Se ha mantenido la igualdad referencial para las variables a través de los bucles de representación y se han considerado los casos de uso en los que ha cambiado.

      • Todas las funciones pasadas a otro componente tienen integridad referencial (no se autoreferencian y por tanto pueden incurrir en un bucle infinito al renderizarse).

      • Se comprende el uso de la integridad referencial en los nuevos hooks agregados: useMemo, useEffect, useCallback deben depender de variables referencialmente estables.

      • No hay efectos (useEffect) que tomen props entrantes y las calculen para un useState local; esto es useMemo con pasos adicionales.

  • Se pasan objetos a componentes que solo necesitan unos pocos atributos (segregación de interfaces).

· One min read
Lucas Fernández Aragón

Overview Docs

Como ya comentamos, esta documentación sirve como apoyo para el Taller Proyecto Web del Máster Full Stack.

Aquí pondremos la documentación pertinente para complementar lo visto en los distintos proyectos:

Así podréis consultar detalles como arquitectura, funcionalidades, dependencias y despliegues que mostramos en clase.

¡Espero que os guste!. Y como siempre, si encontráis errores o mejoras, podéis abrir una issue o proponer una pull request.

· One min read
Lucas Fernández Aragón

Bienvenidos a la documentación del Taller Web.

En blog os enseñaré las funcionalidades de Blog en Docusaurus. Estas herramientas se ejecutan mediante el plugin blog.

Para crear un nuevo blog solo se necesita añadir archivos (o carpetas) al directorio blog.

Los autores de los blog se pueden añadir en el fichero authors.yml.

La fecha del post se puede extraer directamente del nombre del archivo, como:

  • 2019-05-30-welcome.md
  • 2019-05-30-welcome/index.md

Un post creado mediante carpetas puede alojar las distintas imágenes que se quieran usar dentro, como por ejemplo:

Docusaurus Plushie

Además de todo esto, las entradas de blog soportan tags.