+FASE 0 - REACT MENTAL MODEL
TEMA 1 - RENDERIZADO EN REACT: El modelo mental base
- Un componente se renderiza cuando React ejecuta la funcion del
componente para obtener la UI y luego actualiza la pagina para que esa UI
se vea asi
-Esa "descripcion" no es HTML directo. Es una estructura en memoria que
react usa (Conmunmente llamado VIRTUAL DOM)
-SPA (Aplicacion de pagina unica) es una aplicacion web que carga una
sola pagina HTML incial y que luego se actualiza dinamicamente sin
recargar toda la pagina (Con react router dom pues se renderiza el nuevo
componente)
-Pero el SEO es complicado ya que los bots ven HTML vacio inicialmente
-Un componente en React no es mas que una funcion que devuelve objetos
JavaScript que representan pedazos de interfaz
Donde ocurre el renderizado en una app React normal
-Es una app react tipica (Create react app, vite, etc) pasa:
1. Se escribe componentes React
2. Se hace un build y el navegador descarga los archivos estaticos HTML
base, JS ([Link]) o ([Link] en codeSplitting), CSS
3. El navegador ejecuta ese JS
4. React monta tu app dentro un <div id="root">
5. React renderiza componentes -> crea UI -> Actualiza el DOM real
- Con react puro, la interfaz se construye principalmente en el navegador
-Esto se llama Client Side Rendering (CSR): renderizado del lado del
cliente
Resumen del virtual DOM
-Cuando cambia el estado se hace un renderizado:
1. React vuelve a ejecutar el componente (es una funcion)
2. Obtiene un arbol de objetos
3. Compara el nuevo arbol con el anterior (subarbol)(nodo por nodo)
4. Detecta diferencias
5. Aplica solo esos cambios al DOM real
Eso es todo
Que dispara un re-render?
-Cuando cambia su estado (useState)
-Cambia sus props
-Cambia un contexto que usa
-Su componente padre se vuelve a renderizar (no, si el hijo esta
memorizado con [Link])
-En react puro todo esto pasa en el navegador, el html inicial suele
estar vacio hasta que carga el JS
-La primera vez que React renderiza el componente, no hay "foto"
anterior, crear la UI completa por primera vez e inserta elementos al DOM
real
-Con React todo se hace en el cliente, pero con NextJS se puede
renderizar componentes en el servidor, se puede mandar HTML ya listo al
navegador
-En react sin JS la app no existe, en Next puede existir HTML ya listo
desde el servidor (aunque no haya JS todavia)
RESUMEN
-Cuando ejecutamos por ejemplo una aplicacion con vite, que es lo que
sucede? El navegador hace una peticion http del [Link], vite se lo da
y luego el navegador al ver el script main tambien lo pide por http,
entonces vite intercepta esa peticion y convierte ese [Link] a js,
luego se la pasa al navegador. El navegador por los modulos ES para
resolver las importaciones y pedirlas igual por http, de igual forma que
antes vite se las pasa. Ahora que el navegador tiene los archivos
JavaScrip viene el proceso de renderizado.
-Un componente en react (Que ahora es JS en el navegador) no es mas que
una funcion que al ejecutarse retorna un objeto que representa un pedazo
de interfaz. Con estos objetos que retornan las funciones se crea un
arbol de objetos que se denomina el virtual DOM, entonces cuando se
realiza un re-render lo que se hace es que se crea un nuevo arbol de
objetos, el cual se compara con uno anterior para ver y cambiar solo lo
que se modifico. Luego esos cambios se sincronizan con el DOM real. Muy
importante esto sucede cuando la aplicacion esta en funcionamiento.
-Ahora que pasa cuando modificamos un archivo, pues vite notifica al
navegador (por websocket) que archivo fue modificado, entonces el
navegador pide nuevamente por http dicho archivo y vite se lo pasa, se
reemplaza dicho modulo en memoria y se intenta mantener el estado, pero
react vuelve a ejecutar el componente afectado
-Todo esto en desarrollo, pero que pasa cuando se realiza un build o en
produccion?, Cuando hacemos un build se usa un bundler el cual en
resumidas cuentas nos entrega nuestros archivos estaticos (HTML, CSS, JS)
luego de eso supongamos que lo deployamos en netlify, entonces este
servidor sirve estos archivos estaticos y nos da un dominio para que
podamos acceder a ellos. En el navegador cuando entramos al dominio
realiza una peticion http al servidor, el servidor le devuelve un
[Link] y luego en base a sus etiquetas (script y link) hace una
peticion http para obtener el js, el servidor le retorna el bundle, lo
ejecuta, luego hace una peticion http para el css, de igual forma el
servidor le retorna el css, lo ejecuta.
-Y bueno como es evidente todo el renderizado se realiza en el navegador
es por eso que se denomica CSR o renderizado en el cliente
-Este proceso (renderizado) siempre es el mismo no importa si es
desarrollo, produccion, con vite, CRA o cualquier bundle
-El DOM es una interfaz de programacion que representa la estructura de
un documento HTML o XML
-Este DOM o sus objetos estan codificados en c++ o c, generalmente lo que
se usa el JS para interactuar con el DOM es un metodo de una API
(interfaz)
-Como dato curioso una interfaz (por ejemplo en POO) no solo sirve como
contrato con una clase, la interfaz tambien:
-Una interfaz no es mas que un intermediario entre una y otra cosa,
debido que el algo que utilizara a ese otro algo, no le interesa saber
los detalles internos de lo que usara, solo le interesa lo que hace
-Por ejemplo una interfaz grafica no es mas que un intermediario entre el
usuario y la computadora, (ya que al usuario no le interesa los detalles
internos (tampoco entenderia)) sinos unicamente lo que la maquina hace,
por supuesto de una forma que se pueda entender
TEMA 2 - CICLO DE RENDER Y RE-RENDER EN REACT
RE-RENDER
-Significa volver a ejecutar la funcion del componente, no significa
recargar la pagina, no significa borrar el DOM o volver a pedir archivos
-Se actualiza el DOM solo si hay diferencias
CUANDO REACT DETECTA CAMBIOS
-Hay 2 fases principales:
FASE 1 - RENDER PHASE
0. Agenda una actualizacion
1. React ejecuta el componente
2. Genera un nuevo arbol
3. Compara con el anterior
4. Calcula que cambio
FASE 2 - COMMIT PHASE
1. Aplica los cambios reales al DOM
2. Ejecuta efectos (useEffet)
3. Ejecuta refs
-Un componente puede re-renderizarse y no cambiar nada del DOM
STRICT MODE (Solo en desarrollo)
-React puede ejecutar los componente dos veces
-Esto es para detectar errores
-Todo esto es importante porque en Next moderno:
1. Hay componente que se ejecutan en el servidor
2. No todos los re-renders ocurren en el cliente
3. No todos los componentes pueden usar estado o efectos
Primer vistaso a UseEffect
useEffect(()=>{}, [])
- En el render inicial -> Se ejecuta
- En los siguiente re-renders -> No se ejecuta
Cuando tenemos por ejemplo:
useEffect(()=>{
return ()=>{[Link]()}
})
-El return unicamente se devuelve cuando se ejecutara un nuevo useEffect,
entonces ese return corresponde al effect anterior
-El useEffect se ejecuta despues de la fase de commit porque las
operaciones que estan dentro podrian bloquear el renderizado de la
interfaz, como peticiones HTTP, suscribirse a eventos, etc.
TEMA 2.5 - HIDRATACION
-Es el proceso en el que react toma un HTML que ya fue generado
(normalmente por el servidor) y le añade toda la logica de JavaScript
para que el componente sea interactivo
-Este proceso no ocurre con React tradicional, sinos con Client
components en Next.
-El servidor no espera a que el navegador renderice la interfaz, sinos
que la genera y envia el HTML al navegador, luego el navegador descarga
el JavaScript del componente para que sea interactivo y react hace lo
siguiente:
1. React recorre el HTML existente
2. Compara ese HTML con el arbol de componentes (Se vuelve a ejecutar el
componente en el cliente)
3. Si coincide, agrega toda la interactividad
includo los procesos de efectos, estados, etc.
-Ese proceso de conectar React con un HTML ya existente se llama
hidratacion
-Si el HTML no coincide hay un error
-Asi es como funciona un Client Componente dentro de un Server Component.
Renderiza amboslutamente todo en un HTML, se enviar al navegador, y luego
se descarga unicamente el JavaScript del Client Component, luego React
hidrata el componente
OBJECT
-[Link]() // Retorna un arreglo con los valores de las propiedades
del objeto
TEMA 3 - COMPONENTES CONTROLADOS VS NO CONTROLADOS
COMPONENTE CONTROLADO
-Un componente controlado es cuando por ejemplo el valor del input
depende completamente del estado de react
EJM:
function Form() {
const [value, setValue] = useState("");
return (
<input
value={value}
onChange={(e) => setValue([Link])}
/>
);
}
1. El estado vive en React
2. El input muestra el valor del estado
3. Cada vez que se escribe, se dispara onChange, se actualiza el estado,
se re-renderiza el componente, React vuelve a asignar el value
-Aqui React controla complente el input, por eso se llama controlado
COMPONENTE NO CONTROLADO
-Aca el estado vive en el DOM, no en React
-El navegador maneja el valor internamente, React no guarda el estado
-Solo accedemos al valor cuando lo necesitamos
-En NextJS muchas veces no necesitamos estados controlados
-En react clasico pensamos: "Todo debe estar en el estado"
-EN Next moderno: "El estado solo debe estar en el cliente si realmente
se necesita", menos estado = menos re-renders = menos JS enviado
TEMA 4 - HOOKS CLAVE
-Un hook es una funcion especial en react que te permite:
1. Guardar y actualizar estado
2. Ejecutar efectos
3. Acceder a contextos
4. Guardar valores persistentes entre renders (refs)
5. Optimizar renders (memo/callback)
-Solo funcionan dentro de un componente funcion
UseState: estado local del componente
-useState no es es mas que un hooks que te permite guardar valores de un
componente
- Sin useState, un componente es solo una funcion pura que devuelve UI.
Pero una funcion normal no "recuerda" valores entre ejecuciones
UseEffect
-Es un hook que te permite registrar una funcion que se ejecutara cuando
el DOM se actualice
-Se usa generalmente para fetch en el cliente, suscribirte a eventos
(windows, websockets), timers, manipulacion del DOM aunque no es lo ideal
Dependencias
-Sin array: corre despues de cada render
-Con array: Corre en el montaje o primer render
-[x]: corre cuando cambia x
-[x, y]: Corre si al menos una cambia (funciona como OR) (Si varias
cambian ejecuta una sola vez)
-Si retorna una funcion, React lo ejecuta antes de correr el siguiente
efecto o cuando el componente se desmonta
UseContext: Leer valores globales compartidos
-Es un hook que te permite guardar y leer valores globales compartidos
-Evita pasar props manualmente por muchos niveles (prop drilling)
-El componente se re-renderiza cuando cambia el valor del Provider
-Es ideal para estados globales que cambian poco, lo podemos usar como
zustand o redux creando multiples contextos pero puede escalar mal en
cuanto a codigo y rendimiento
UseRef: Memoria persiste sin causar re-renders
-Es un hook que te permite acceder a un elemento del DOM y te permite
guardar valores entre renders
-Cuando se actualiza su valor no dispara un render a diferencia del
useState (Porque si)
UseMemo: Memorizar un valor (evitar recalcular)
-Es un hook que te permite recordar un valor, evitando recalcular en cada
render mientras no cambien las dependencias
UseCallback: Memorizar una funcion (evitar que cambie de referencia)
-Es un hook que te permite memorizar una funcion, ya que es JS una
funcion dentro de un componente es una nueva en cada render
-Sirve especialmente cuando: pasas callbacks a hijos memorizados
-En Next moderno hay 2 tipos de componentes, Server components y Client
components "use client", aca si existen los hooks
TEMA 5 - LIFTING STATE
-Es mover el estado hacia arriba en el arbol para compartirlo
-Si dos compontens necesitan el mismo estado, ese estado debe vivir en su
ancestro comun mas cercado
Problema
-Si se levanta estado innecesariamente: El padre se vuelve grande, cada
cambio re-renderiza mas componentes, se vuelve dificil de mantener
Regla
-Es estado debe vivir en el lugar mas bajo posible del arbol, no mas
arriba de lo necesario
-Incorrecto:
function App() {
const [isOpen, setIsOpen] = useState(false);
return <Modal isOpen={isOpen} setIsOpen={setIsOpen} />;
}
-Este estado deberia vivir en modal
Composition
-Es construir UI (componentes) reutilizable, el componente no necesita
saber todo lo que contiene
-Podemos implementarlos pasandole props o children
-Si la estructura es fija -> props esta perfecto
-Si quieres permitir contenido arbitrario -> Children mejor
TEMA 6 - SUSPENSE EN REACT
-Es un mecanismo que permite mostrar un fallback cuando un componente
(subarbol) se suspende en la fase de render
-Durante la suspension, React nuestra un fallback
-Solo reemplaza temporalmente la parte que no esta lista
-Suspense solo actua si durante la fase del Render se lanza un Promise
(Pero casi nunca sucede)
-Un fallback no es mas que interfaz alternativa que React muestra
mientras un componente esta suspendido
-React continua renderizando normalmente el resto del arbol cuando un
componente se suspende
<Suspense fallback={<p>Cargando...</p>}>
<Componente />
</Suspense>
-Si un componente no puede renderizar todavia, react muestra el fallback
LAZY LOADING
-Es no cargar algo hasta que realmente se necesite
-Lo mas comun es lazy loading de componentes
-Cuando el componente no esta listo debido a que tiene una carga
perezosa, ese componente se suspende
Flujo
1. Durante la fase de renderizado, React intenta renderizar el componente
que esta con lazy, pero lazy aun no tiene el modulo o archivo cargado
2. import("./HeavyComponent") devuelve un promise
3. React detecta que hay una promise en render, dice "Este subarbol no
esta listo todavia", por tanto busca el Suspense mas cercano arriba, y en
lugar de continuar con el render, renderiza el falback
4. En paralelo el navegador descarga el chunk JS correspondiente a
HeavyComponent
5. El archivo termina de descargarse y la promise se resuelve, se
reintenta renderizar ese componente y el render continua normalmente
-Si hay lazy sin suspense, se lanza un error porque React no sabe que
mostrar
-Suspense solo dice "si algo se suspende, yo me encargo del fallback"
BUILDING
-Bundle no siempre significa un solo archivo
-Cuando hacemos el build, se hace code splitting automatico, no genera un
solo archivo gigante, sinos que divide la app en multiples archivos
(chuncks)
-Cada import() dinamico crea un chunk separado
-Cuando React intenta renderizar el componente lazy, el chuck aun no esta
descargado, se dispara una peticion http por ese archivo JS
-Mientras tanto se muestra el fallback hasta que el chunk termina de
descargarse
-Si el componente lazy ya fue descargado una vez, no se vuelve a
descargar, el navegador lo tiene cacheado (Por tanto no se muestra un
fallback)
-Code splitting es divir el codigo JS en multiples archivos (chunks) en
lugar de uno solo ([Link]), se activa cuando se usa imports dinamicos
con lazy
-El Code Splitting lo hace el bundler, ellos analizan el codigo y generan
los chunks
TEMA 7 - SEPARACION DE LOGICA EN REACT(UI, DATOS, NEGOCIO)
[Link] DE UI
-Es todo lo que tiene que ver con: Que se muestra, como se muestra,
condiciones visuales, renderizado
EJM:
if (!user) return <Spinner />;
return <h1>{[Link]}</h1>;
[Link] DE DATOS
-Es como se obtiene los datos
EJM:
fetch("/api/user")
[Link] DE NEGOCIO
-Es como transformas o decides cosas con los datos
-Basicamente operaciones con los datos
EJM:
if ([Link] === "admin") {
// mostrar panel especial
}
POR QUE SEPARALAS
-El componente crece demasiado
-Dificil testear
-Dificil reutilizar
-Es dificil cambiar el origen de los datos
-Lo que se debe hacer es separar la logica de datos en Custom hooks:
function useUser() {
const [user, setUser] = useState(null);
useEffect(() => {
fetch("/api/user")
.then(res => [Link]())
.then(setUser);
}, []);
return user;
}
SEÑALES
-Si el componente tiene 5 useEffect, 8 estados distintos, varios fetch,
mucha logica condicional
-Un buen componente React deberia ser una funcion que recibe datos y
devuelve UI, no un minibackend
LOGICA DE NEGOCIO
-Como separarla?
1. Hacer una funcion externa y dentro del componente solamente llamarla
(Si el proyecto no es muy grande se lo puede poner fuera del componente)
(Para proyectos mas grande se aplica el 3 que basicamente es lo mismo)
2. Dentro de un custom hook si la logicca esta relacionado con estados o
efectos
3. En un archivo de dominio separado
-No es buena practica lo siguiente:
return (
<div>
{[Link] === "admin" && <AdminPanel />}
</div>
);
-No es buena practica si esa logica de negocio se repite en muchos
lugares, si puede cambiar en el futuro o es muy importante
-Lo normal seria llevarlo a una funcion o a un custom hook
-A veces si es necesario dejar los useState en el componente ya que
muchos otros lo utilizan (orquestacion)
CUSTOM HOOK
-Aveces no solo hay estos tipos de logica, muchas veces hay logica de
configuracion, logica relacionada con el estado, efectos o comportamiento
reutilizable como debounce o localStorage. Entonces estos pueden ir en el
hook
EN RESUMEN
-Un componente solo deberia recibir datos y retornar UI para que sea
mantenible, escalable, testeable, reutilizable y facil de leer
-Asi mismo reducir acoplamiento entre logicas
-Todo gira alrededor de la UI
-Un componente deberia ser tonto en lo posible pero en ciertas
situaciones puede tener estado/logica:
[Link] local de UI: Abrir/cerrar modal, paginacion local
[Link] componente cuya responsabilidad es orquestar:Llamar hooks, juntar
datos y pasar props
[Link] muy pequeña y especifica de tal forma que no haga crecer mucho
el componente
TEMA 8 - OPTIMIZACION EN REACT
-React ya evita actualizar el DOM innecesariamente, mucho re-renders NO
significan muchos cambios en el DOM
-React solo actualiza lo necesario en base al virtual DOM, pero si hay 2
cosas que pueden afectar performance
1. Calculos costosos en cada render
const sorted = [Link]((a, b) => b < a)
-Puede ser costoso si se ejecuta en cada render
2. Re-render en cascada
Si un estado vive muy arriba, cada cambio re-renderiza todo el arbol
debajo
3. Props que cambian referencia constante
<Child onClick{() => doSomething()}>
-Esta funcion se crea en cada render, si child esta memorizado, eso rompe
la memoizacion
HERRAMIENTAS
REACT MEMO
-Evita que un componente se re-renderice si sus props no cambiaron, React
compara props superficialmente (Esto solo aplica a los props)
const Child = [Link]((props) => {});
USE MEMO
-Memoiza un valor el cual si recalcula solo si cambia la dependencia
const sorted = useMemo(()=>[Link](), [bigArray]);
USE CALLBACK
-Memoiza una funcion, evita que la funcion cambie referencia en cada
render mientras que las dependencias no cambien
-En JS las funciones son objetos y en cada render en un objeto nuevo en
memoria por tanto su referencia cambia, esto hace que el child piense que
las props cambiaron si usa dicha funcion
const handleClick = useCallback(()=>{}, [id])
-Se debe usar solo cuando es necesario, si no puede hacer el codigo mas
complejo, no mejorar nada o incluso empeorar el performance levemente
KEYS EN LISTAS
-La key ayuda a React a identificar elementos entre renders y evitar
reconstrucciones innecesarias
-No usar key={index} si el orden de los elementos puede cambiar
-Puede mezclar estados internos
LAZY LOADING
-Ayuda a no cargar todo el codigo al incio y reducir el tamaño del bundle
incial
FASE 1 - FUNDAMENTOS DE [Link]
-[Link] no es una libreria como React
-Es un framework full-stack construido sobre react
-Un framework es una marco de trabajo que define estructura,
convenciones, integra herramientas y toma decisiones por ti. React solo
se encarga del render
-Tu tienes que seguir esa estructura, convenciones, usar esas
herramientas para tener la maxima productividad
-Libreria es mas flexible pero mas decisiones que tomar
-Next se encarga de Routing, renderizado, data feching, optimizacion,
Bundling, backend, deploy optimizado
REACT VS NEXT
React
1. SPA
2. Todo se renderiza en el cliente (La app vive en el navegador)
3. Fetch en useEffect
4. El servidor solo sirve archivos
5. Configuracion manual del router
Next
[Link] hibrido (Cliente + servidor) (La app puede vivir en el servidor
y en el cliente)
[Link] automatico por archivos
[Link] automatica
[Link] splitting automatico
[Link] integrado
[Link] (renderizado en servidor)
INSTALACION
-npx create-next-app@latest nombre-proyecto
META TAGS
-Las etiquetas Meta son etiquetas HTML que se usan para proporcionar
informacion adicional sobre una pagina a los motores de busqueda y a
otros clientes
export const metadata : Metadata = {
title:"SEO FRIENDLY",
description: "Products Page",
keywords: ['Mouse', 'screen']
}
-Podemos poner metadata en cada page de forma especifica, si un page no
lo tiene entonces lo toma en de el padre mas proximo
-Para que la metadata sea dinamica en base a la pagina donde nos
encontremos podemos hacer lo siguiente:
export async function generateMetada({params}: Props): Promise<Metadata>{
const {id, name}=getPokemon ([Link]);
return{
title: `${id} - ${name}`,
description: ``,
}
}
-Esto lo debemos poner fuera del funtional component
ESTRUCTURA BASICA MODERNA
app/
[Link]
[Link] #Pagina principal (/)
dashboard/ #ruta /blog
[Link]
settings/ #/dashboard/settings
-Para proyectos grandes la mejor es por features y app solo routing. Si
es pequeño pues en el app normalmente y en el componentes compartido una
clara separacion
Regla
-En next moderno, todo es Server Component por defecto, es decir no se
puede usar useState u otro hook sin "use client"
TEMA 2 - APP ROUTER Y ROUTING BASADO EN ARCHIVOS
-App router es el sistema de rutas basado en la carpeta app
-En Next moderno (App Router) las carpetas son las rutas
/ -> app/[Link]
/dashboard -> app/dashboard/[Link]
Layout
-Un layout es un componente que te permite definir una estructura comun
que se comparte entre multiples paginas
-Es util para evitar repetir codigo y mostrar elementos que se quiere que
aparezca en todas o varias paginas
-Es un layout compartido para las rutas debajo, el layout puede envolver
varias paginas
app/[Link]
app/dashboard/[Link]
EJM:
// app/dashboard/[Link]
export default function DashboardLayout({ children }) {
return (
<div>
<aside>
{/* Sidebar solo para el dashboard */}
<nav>Panel de Control</nav>
</aside>
<div>{children}</div>
</div>
)
}
-children representa el contenido de la pagina actual que se esta
renderizando. [Link] para automaticamente el contenido de cada pagina
como children al layout correspondiente
LINK
Como navegar entre rutas?
import Link from "next/link"
<Link href="/dashboard">Ir al dashboard</Link>
-Cuando estamos en desarrollo, next hace un prefetch de las paginas de
los "Link" cuando pasamos el mouse sobre ellos, pero en produccion hace
un prefetch cuando <Link> entra en el viewport (Cuando es visible)
-Todo esto hace que la experiencia se sienta como un SPA
-Podemos habilitar o desabilitar el prefetch
REDIRECT
-Podemos hacer navegacion programatica con lo siguiente:
import {refirect} from "next/navigation"
redirect('/dashboard/counter');
CSS MODULES
-Es una forma de escribir css de tal forma que el scoop o el contexto de
los nombres
-Cuando utilizamos esta etiqueta, el comportamiento de la navegacion es
similar al de un SPA
-Lo que se hace es un prefetch de la pagina una vez hacemos un hover a su
link
IMAGE
-Requiere src, width, hright y alt
-Tiene ventajas como optimizacion automatica de imagenes, Lazy loading
por defecto
-Para utilizar imagenes de otros dominios al de la aplicacion debemos
especificarlo en el [Link]:
images: {
remotePatterns: [
{
protocol: "https",
hostname: "[Link]",
},
],
},
<Image
priority = {false}
placeholder="blur"
onLoad={...}
/>
-Con esta propiedad la imagen es cargado bajo demanda, es decir cuando se
encuentre en el viewport (Por defecto lo tiene)
-Se lo puede poner un loader con placeholder u onLoad (React tambien lo
tiene)
ERROR
-Se puede poner un [Link] en cualquier directorio con page
-Debe ser un client components
export default function Error({error, reset}: {error: Error, reset: () =>
void}){
return<></>
}
DEPURACION DE CODIGO - BREAKPOINTS
-Se puede depurar el codigo de Next, para eso debemos poner breakpoint y
luego iniciar la dupuracion en [Link]
NOT-FOUND
-Al igual de una pagina de error o un [Link] podemos tener paginas
[Link] por ruta
-Podemos tener uno general en el app y otros mas especificos
-Podemos mandar a llamar la pagina de not-found de la siguiente forma:
import {notFound} from "next/navigation";
try{
}catch(error){
notFound();
}
USE ROUTER
-Es un hook de [Link] que te permite acceder al router y realizar
navegacion programatica (Cuando se cambia de pagina usando codigo JS en
lugar de que el usuario haga click en un Link)
import {useRouter} from 'next/navigation'
const router = useRouter();
[Link]('/dashboard') - Navegada a una nueva pagina
[Link]() - Vuelve a la pagina anterior
const {id} = [Link] //Acceder a las querys de la URL
[Link] //Obtener la ruta actual
RUTAS DINAMICAS
Rutas dinamicas o parametros dinamicos
- Se crea con corchetes []
app/
articulo/
[id]/ ← Carpeta con corchetes = parámetro dinámico
[Link]
-El parametro se recibe como prop en la pagina:
export function ArticuloPage({params}){
const {id} = params
}
-{params:{id: 4}, searchParams:{age:10}}
-No siempre puede ser un "number", en ocaciones /blog/lo-que-sea / Se
tiene 1 parametros
-En [Link] solo existe una ruta si hay un [Link] incluso si existe la
carpeta
-Como es una pagina dinamica, entonces al hacer el build Next no puede
pre-renderizar estaticamente la pagina, por tanto en runtime cuando se
hace la solicitud la renderiza y luego se aplica la estrategia
correspondiente de renderizado (SSR, SSG, ISR)
-Ahora bien, podemos generar todas las paginas dinamicas si ya sabemos
cuales son los Params
export async function generateStaticParams(){
return [
{id: '1'},
{id: '2'},
]
}
export async function generateStaticParams(){
const pokemonsData = await fetch()...
const pokemons = [Link](pokemon => [Link]);
return [Link](name => {name});
}
-Puede ayudar mucho a mejorar el rendimiento de la pagina asi como
tambien el SEO
-No tendria mucho sentido si los datos cambian con frecuencia y usamos
SSR
-Para el SEO es mucho mejor utilizar slug que es como texto
identificativo pero mas informativo que un id
USE CACHE
-Es una directiva que te permite cachear resultados de funciones en caso
los parametros sean iguales
-React tambien lo tiene pero es para deduplicar llamadas durante una
peticion o render
-En cambio el "use cache" es tambien para eso pero tambien para
reutilizar resultados entre llamadas de peticiones pero siempre con
reglas claras de revalidacion e invalidacion del cache
import { cacheLife, cacheTag, revalidateTag } from "next/cache"
cacheLife({
stale: 3600, // 1 hr
revalidate: 7200 // 2 hours
expire: 86400
})
cacheTag('pokemons')
revalidateTag('pokemons, 'max');
-La revalidacion es algo importante ya sea en este caso con "use cache" o
con ISR, ya que permite que la cache este actualizada y no obsoleta
-Hay 2 formas de hacerlo, uno de manera automatica por tiempo y otra
manual a travez de un webhook, es decir, despues de la operacion de
modificacion por ejemplo
TEMA 3 - LAYOUTS
-Un layout es un componente que define una estructura comun que se puede
compartir entre multilples paginas
-Envuelve las paginas [Link]
-children representa el contenido de la pagina actual que se esta
renderizando. [Link] para automaticamente el contenido de cada pagina
como children al layout correspondiente
-El estado dentro del layout se mantiene
LAYOUTS ANIDADOS
RootLayout
└── DashboardLayout
└── [Link]
-Funcionan asi basicamente
-Normalmente en un Root layout vive <html> <body>, providers globales
(Theme, Auth, navbar global)
-En layout por seccion viven Sidebar, header interno, layout grid
TEMA 4 -SERVER COMPONENTS VS CLIENT COMPONENTES
SERVER COMPONENTS
-Es un componente que se ejecuta en el servidor, no envia su codigo JS al
navegador
-Son componentes que solo muestran informacion y no cambian por acciones
del usuario
-En el App router todo es server component por defecto si no se escribe
"use client" arriba
Hooks del cliente
-useState -> Solo se puede usar en el navegador, ya que necesita un ciclo
de vida interactivo
-useEffect -> Solo ejecuta despues del commit al DOM del navegador
-useRef(Para referenciar al DOM) -> No existe DOM en el servidor
-useRouter -> Necesita interactuar con el historial del navegador y hacer
navegacion programatica
-eventHandles tampoco funcion en server-componentes
-El servidor no se re-renderiza
export default async function Page(){
const response = await fetch("");
const data = await [Link]();
return <div>{[Link]}</div>
}
FLUJO
-Servidor ejecuta componente
-Genera HTML
-Envia HTML al navegador
-Se destruye
-No envia JS innecesario
CLIENT COMPONENTS
- Se ejecuta en el navegador
- Tiene interactividad (responden a acciones del usuario o cambian su
contenido dinamicamente)
- Puede usar hooks
- Se envia como JS al cliente
-Solo utilizar Client si se necesita interactividad
-En proyectos grandes el 70-90% deberian ser Server Componentes, Client
solo para formularios interactivos, modales, Dropdowns, estados UI
COMPONENTES MIXTOS
-Se puede tener Server Components que contengan Client Components pero no
viceversa (Obvio porque el codigo ya esta en el navegador por tanto se
vuelve client component)
-El server component vive en el servidor y el client component vive en el
cliente, por tanto solo se envia el JS de ese componente. Todo esto
reduce mucho el bundle
TEMA 5 - RENDERIZADO EN [Link]
-Existen varios modos de renderizado
-Hay 2 dimensiones diferentes en NEXT
Donde se ejecuta el componente
-Server Component
-Client component
Cuando se ejecuta el componente
(Esto solo se aplica a Server Components)
-En cada request (SSR)
-En build (SSG)
-Cada cierto tiempo (ISR)
-El comportamiento de renderizado se decide segun como uses fetch
-Next usa fetch como señal para saber: Es contenido cacheable? es
dinamico? debe regenerarse?
-Si no tiene fetch, no tiene datos dinamicos, se vuelve estatico
automaticamente (SSG automatico)
Browser → Request → Server
Server ejecuta Server Components
Server → HTML → Browser
-Ese es el flujo que describe una carga inicial de pagina, pero lo que
cambia entre SSR, SSG, ISR es: El servidor ejecuta el componente en ese
momento o solo entrega algo ya generado?
1. SSR - SERVER SIDE RENDERING
-Se ejecuta el componente en el servidor en cada request
1. Request al servidor
2. Se ejecuta el componente
3. Se genera HTML
4. Se envia al navegador
EN APP ROUTER QUE ACTIVA SSR?
-Cuando se usa cache: "no-store"
await fetch("[Link] {
cache: "no-store"
})
-Esto le dice a Next que no se cachee esto y que lo ejecute siempre en
cada request
VENTAJAS
-Datos siempre actualizados
-Ideal para dashboards, datos del estudiante logueado
DESVENTAJAS
-El servidor trabaja en cada request, mas uso de CPU
-Menos escalable que estatico
2. SSG - STATIC SITE GENERATION
-Significa que el componente se ejecuta en build time o en el primer
request (en desarollo)(Con rutas dinamicas igual)
-Es decir cuando se hace npm run build
1. npm run build
2. Ejecuta el componente
3. Hace los fetch
4. Genera los HTML
5. Guarda los HTML en disco / CDN
-El usuario entra y el servidor retorna el HTML ya generado y almacenado
en el file system
-Por defecto Next cachea el fetch, eso produce comportamiento estatico
VENTAJAS
-Ultra rapido
-Escala infinito
-Perfecto para blogs, landing pages
DEVENTAJAS
-Los datos no cambian hasta el proximo build
3. ISR - INCREMENTAL STATIC REGENERATION (combina estático+dinámico)
-Genera estatico, pero permite regenerarlo cada cierto tiempo
await fetch("[Link] {
next: { revalidate: 60 }
})
-Se genera estatico pero dicha version solo sirve 60 segundos
-Despues de ese tiempo, el siguiente request dispara regeracion
-Se actualiza en 2do plano
1. Primer usuario Genera HTML
2. Usuarios siguientes reciben HTML cacheado
3. Despues de 60 segundos se dispara regeneracion
VENTAJAS
-Ideal para noticias, productos, catalogos, datos que cambiar pero no en
tiempo real
4. STREAMING
-Es sobre como se envia el HTML, se puede enviar partes mientras otras se
siguen generando
-Header(rapido), Sidebar(rapido)
-Se usa con Suspense y [Link]
-TODO Esto es para todos los usuarios, no para uno en especifico, es
decir que si se crea otro build con ISR, es global para todos
ROUTE GROUP
-Son una forma de organizar rutas en carpetas sin que afecten a la URL
final, se crean usando parentesis:
(marketing)
(auth)
-Solo sirve para estructura y organizacion
UTILS
-Son funciones genéricas y puras que no están atadas a tu dominio de
negocio. Podrías copiarlas a cualquier proyecto y funcionarían igual.
HELPERS
-Son funciones que sí conocen tu dominio o contexto. Están atadas a tu
aplicación específica.
TIPS
-No se debe hacer esto, se pierde consistencia, dificil de escalar y se
ve amateur: className="text-[17px]"
-En tailwind se puede usar dark por preferencia, shadcn lo usa por clase
-En tailwind los tokens son valores del sistema de diseño, datos crudos,
las utilities son clases de css que consumen los tokens
-Se debe usar recomendablemente Shadcn para UI primitivo como: Botones,
inputs, textareas, select, dialog, dropdownMenu, tabs, sheets, Card
- No es recomentable cambiar tamaños de shadcn
FASE 2 - DATA FETCHING
REACT
-Con react tradicional se debe hace lo siguiente
useEffect(()=>{
fetch("/api/jobs")
}, [])
-Primero el componente se renderiza datos, luego hace fetch y guardamos
los datos, por lo tanto se hace un re-render, todo esto sucede en el
cliente por tanto se tiene un JS pesado
NEXT
-El fetch puede ocurrir en el servidor antes de que el HTML llegue al
navegador, sin enviar JS innecesario al cliente
EJM:
export default async function JobsPage() {
const res = await fetch("[Link]
const jobs = await [Link]()
return (
<div>
{[Link](job => (
<div key={[Link]}>{[Link]}</div>
))}
</div>
)
}
ESTO ELIMINA PROBLEMAS CLASICOS EN SPA
-No hay hooks, no hay loading manual, no hay doble render. El HTML ya
llega con los datos por tanto no hay SEO pobre. JS inncesario
ASYNC COMPONENTS
-En react normal no se puede hacer esto, pero en NEXT si
-Esto convierte al componente en una funcion que produce HTML despues de
esperar datos
-Es SSR mejorado
TEMA 2 - CACHE EN NEXT
-La cache vive en el servidor
-En un server component el fetch no es el fetch normal del navegador
-Es un fetch extendido por NEXT y por defecto tiene cacheado automatico
-Eso significa que los datos puede guardarlos y reutilizarlos, tambien
significa que la pagina puede convertirse casi estatico
EJEMPLOS APLICADO AL MARKETPLACE
-Pagina publica de pasantias -> ISR, ya que no cambia en cada segundo, no
necesita real-time y merjor performance
-Perfil de estudiante logueado -> SSG, es privado y especifico del
usuario
-Panel de empresa -> SSG
TEMA 3 - LOADING Y ERROR UI
-En react tradicional:
const [loading, setLoading] = useState(false);
-Se maneja el loading, error y estados intermedios manualmente
-En next en la mayoria de los casos no es asi
[Link]
-Si tenemos un [Link], next lo detecta automaticamente y lo usa como
fallback mientras espera el fetch del Server Component
EJM:
export default function Loading(){
return <p>Cargando pasantias...</p>
}
-Recomendacion en React: Es mejor tener Suspense por componente, no uno
global. La razon principal es la experiencia de usuario: Un suspense
general bloque toda la UI (Incluso lo que ya cargo) mientras carga
cualquier parte, mientras que uno por componente permite que el resto de
la pagina sea interactiva
EJM:
<Header /> {/* sin suspense, carga inmediato */}
<Suspense fallback={<ContentSkeleton />}>
<MainContent />
</Suspense>
<Suspense fallback={<SidebarSkeleton />}>
<Sidebar />
</Suspense>
-Lo ideal es ambos combinados, uno general en el layout y otro por
componente
FLUJO
1. Page hace await fetch(...) y tarda...
2. Next empieza a enviar HTML
3. Muestra [Link]
4. Cuando llegan los datos
5. Reemplaza esa parte
-Esto se llama Streaming + Suspense
-Tambien se denominca Render progresivo
[Link]
-Next automaticamente captura errores del subtree
EJM:
"use client"
export default function Error({ error }) {
return <p>Algo salió mal.</p>
}
-Error debe ser Client Component porque maneja interaccion (retry)
SUSPENSE REAL
-En react el suspense era limitado, en NEXT Suspense funciona en el
servidor, puede dividir el arbol y transmitir partes independientes
-El suspense en NEXT. Divide el HTML en chunks (Streaming basicamente),
primero se envia lo que esta listo, luego se envia lo que aun faltaba por
terminar (solo el pedazo de html) Y reemplaza el fallback
TEMA 4 - SERVER ACTIONS
-Son funciones que se ejecutan en el servidor y que te permiten hacer
operaciones backend en la app
-Se pueden llamar directamente desde un formulario
-No se necesita crear una API manual, no se necesita hacer un fetch
manual
-Es como tener un backend dentro de la app
EJM:
// app/jobs/[id]/[Link]
export async function applyToJob(formData: FormData) {
"use server"
const jobId = [Link]("jobId")
// Aquí iría tu lógica:
// Guardar en base de datos
// Validar sesión
// etc.
}
Y en el formulario:
<form action={applyToJob}>
<input type="hidden" name="jobId" value={[Link]} />
<button type="submit">Aplicar</button>
</form>
-Cuando el navegador envia el form, Next lo intercepta y ejecuta la
funcion en el servidor
VENTAJA
-Menos JSON intermedio, menos endpoints, mejor tipado y mejor seguridad
(la funcion nunca llega al cliente)
-Con revalidate se debe esperar el tiempo definido hasta actualizarse.
Con server actions al final se pone revalidatePath("/jobs") y se invalida
la cache inmediatamente, la lista se actualiza al instante
DESVENTAJAS
-Solo funcionan en server componentes
-No reemplaza completamente APIs externas
-No sirven si necesitas exponer endpoint publicos
-Solo brillas en casos simples
-En react los componentes deben ser en mayusculas, sinos los interpreta
como elementos HTML
REPASO CSS
POSITIONS
-La propiedad position controla como se coloca un elemento en la pagina
position:static
-En el valor por defecto, se coloca siguiente el flujo normal del
documento
-No es posible usar top, right, bottom o left
position:relative
-El elemento mantiene su espacio original
-Se puede mover con top, left, right, bottom
-Se pone relativo a su posicion original
-Es muy usado como referencias para elementos absolute
position:absolute
-El elemento sale del flujo normal por tanto no deja espacio en el layout
-Se posiciona con respecto a su contenedor padre con position distinto de
static, si no existe entonces al body
position:fixed
-Sale del flujo normal, ya que se posiciona con respecto a la ventana del
navegador
-No se mueve aunque se haga scroll
position:sticky
-Es una mezcla de relative y fixed
-Se comporta como relative hasta que alcanza un limite (ej:top:0)
-Luego se comporta como fixed
PROVIDER
-Es un componente que provee de un contexto a sus componentes hijos
-En HTML es un error tanto semantico como de accesibilidad anidar
elementos interactivos entre si
-La solucion es elegir uno de los 2 elementos y darle estilo o
comportamiento del otro, como un boton que se usa como Link
OBJECT
-[Link]() convierte un objeto en un array de pares [clave, valor]
EJM:
const objetito = {nombre: "john", edad: 2};
[Link](objetito) -> [["nombre", "john"], ["edad", 2]]
-[Link]() hace lo contrario, convierte un array de pares
[clave, valor] en un objeto
EJM:
const arraycito = [["nombre", "john"], ["edad", 2]];
[Link](arraycito) -> //{nombre: "john", edad: 2}
FORM DATA
-Es una clase nativa del navegador que representa datos de un formulario
como pares clave->valor
1.A partir de un formulario HTML(lo mas comun)
const formData = new FormData([Link]);
internamente // [["email", "john@[Link]"], ["password", "123"]]
2. Manualmente
const formData = new FormData();
[Link]("email", "juan@[Link]")
-Cuando se le pasa <form>, FormData recorre todos los <input> y toma su
atributo name como clave y su value como valor
[Link]("email") //Obtener un valor
[Link]("email", "otro") //Modificar un valor
[Link]("email") //Eliminar un campo
[Link]("email") //Verificar si existe
-para JSON normal basta con [Link](formData) pero cuando se
necesita subir imagenes o archivos, FormData es la unica opcion porque
soporta datos binario
RECOMENDACIONES
-Siempre se debe usar Link si hacemos navegacion interna en nuestra
pagina y "a" si el enlace es externo a la aplicacion o si se necesita
abrir en una pestaña nueva
-Para rutas internar, a recarga la pagina perdiendo el estado y hace la
navegacion mas lenta
-asChild es un propiedad de shadcn que permite anidar elementos
interactivos, el elemento que lo tenga transfiere su comportamiento y
estilos al hijo y basicamente se convierten en uno solo(elemento hijo)
ROUTE HANDLER
-Es posible en Next crear RESTful Api
-Lo debemos poner dentro de app y en un directorio diferente al de un
page
-Podemos poner en app/api/[Link]
import { NextResponse } from "next/server";
export async function GET(){
return [Link]({
method: 'GET',
count: 100,
});
}
COMO MANDAR DATOS DEL SERVIDOR A REDUX
-Podemos usar los routes handlers
useEffect(() => {
getPokemons().then(data => dispatch(initialPokemonState(data)));
}, [])