Documentos de Académico
Documentos de Profesional
Documentos de Cultura
ARQUITECTURA FLUX
Es una arquitectura para el manejo y el flujo de los datos en una aplicación web,
particularmente en el Front-End. Fue ideada por Facebook y vendría a sustituir el patrón
MVC (o MVVM).
El patrón MVC para el Front-End empezó a ser necesario cuando las aplicaciones web
empezaron a hacerse más grandes y con librerías como jQuery o el propio Vanilla
JavaScript se hacían difíciles de manejar. Por eso nacieron frameworks como Backbone,
Ember y/o Angular.
Todos ellos siguen una arquitectura Modelo-Vista-Controlador, o algo parecido (MVVM,
MV*). Haciendo más sencillo el manejo de datos en aplicaciones web con cierto grado de
complejidad.
Flux nació desde Facebook por un problema que se les presentaba al tener una
comunicación bidireccional entre los modelos y los controladores, haciéndoles muy difícil
poder depurar y rastrear errores.
Flux propone una arquitectura en la que el flujo de datos es unidireccional. Los datos
viajan desde la vista por medio de acciones y llegan a un Store desde el cual se actualizará
la vista de nuevo.
Al igual que un patrón MVC está formado por un Modelo, una Vista y un Controlador, en
Flux tenemos distintos actores:
Vista
La vista serían los componentes web, ya sean construidos nativamente, con Polymer, con
Angular, React, etc...
Store
No hay métodos en la Store que permitan modificar los datos en ella, eso se hace a través
de dispatchers y acciones.
Acciones
{
type: 'ADD_ITEM',
item: item
}
Dispatcher
Las acciones como la anterior son enviadas a un dispatcher que se encarga de dispararla o
propagarla hasta la Store.
Un dispatcher no es más que un mediador entre la Store o Stores y las acciones. Sirve
para desacoplar la Store de la vista, ya que así no es necesario conocer que Store maneja
una acción concreta.
La vista, mediante un evento envía una acción con la intención de realizar un cambio en
el estado
La acción contiene el tipo y los datos (si los hubiere) y es enviada al dispatcher.
El dispatcher propaga la acción al Store y se procesa en orden de llegada.
El Store recibe la acción y dependiendo del tipo recibido, actualiza el estado y
notifica a las vistas de ese cambio.
NODE JS
VITE
Veamos que es JS X es una extensión del lenguaje desarrollada por Facebook (que hoy en
día se conoce como meta )para React
Ahora, como vimos en el video anterior, parece código de JavaScript, pero muestra código
HTML.
Básicamente es un lenguaje de templates que muestra el HTML, pero tiene todas las
funciones de JavaScript.
Una vez compilado, una vez que creas el Bond ,asi se le conoce para publicar tu proyecto
en React,
todos estos pasan a ser archivos JS con funciones y objetos normales, pero cuando estás
desarrollando utilizas JSX.
Con todas estas ventajas de tener el HTML y el JavaScript en un solo lugar, existen ciertas
reglas a la hora de escribir jsx. Los Nombres de los componentes deben comenzar con
mayusculas
A diferencia de HTML que HTML no es para nada estricto, no te puedes crear un DIV y ni
siquiera lo cierras y HTML no te dice nada bueno en jsx, Si una etiqueta HTML tiene
apertura, tienes que agregarle también el cierre.
Lo importante es que, por ejemplo, existen etiquetas de solo apertura, no como, como IMG
o como input. Estos deben de finalizar con diagonal y finalmente el signo de mayor que.
Y algo importante es que en este return debe haber máximo un solo elemento en el nivel
más alto.
Tus componentes en react se van a dividir en dos partes, lo que está antes del return.
Hay puedes colocar código JavaScript como lo conoces. Funciones XYZ, etc. y lo que
está dentro del return, la segunda es lo que está dentro del return es lo que se va a ver en
pantalla. Los componentes llevan la extension JS y en Vite deben llevar la extension jsx
y se importan con un import de javascritp.
Ejemplo
function App() {
cosnt edad=18;
return (
<div className="App">
//{{1+1}
<h1>Hola Mundo</h1>
</div>
function formatName(user) {
return user.firstName + ' ' + user.lastName;
}
const user = {
firstName: 'Harper',
lastName: 'Perez'
};
const element = (
<h1>
Hello, {formatName(user)}! </h1>
);
Esto significa que puedes usar JSX dentro de declaraciones if y bucles for, asignarlo a
variables, aceptarlo como argumento, y retornarlo desde dentro de funciones:
function getGreeting(user) {
if (user) {
return <h1>Hello, {formatName(user)}!</h1>; }
return <h1>Hello, Stranger.</h1>;}
También puedes usar llaves para insertar una expresión JavaScript en un atributo:
Advertencia:
Dado que JSX es más cercano a JavaScript que a HTML, React DOM usa la convención de
nomenclatura camelCase en vez de nombres de atributos HTML.
Si una etiqueta está vacía, puedes cerrarla inmediatamente con />, como en XML:
Estos objetos son llamados “Elementos de React”. Puedes pensar en ellos como
descripciones de lo que quieres ver en pantalla. React lee estos objetos y los usa para
construir el DOM y mantenerlo actualizado.
Reactividad
Cada vez que se actualizan los datos, la interfaz de usuario lo hace automáticamente para
que coincida con la lógica de programación de la aplicación.
Estado
Porque tiene una duración determinada, el estado son datos en un momento particular de la
aplicación, por ello decimos: el estado actual de los datos de la aplicación.
Una interfaz basada en el estado, es aquella que usa los datos de la aplicación en todo
momento para pintar su elementos visuales.
Componentes
Van a permitir dividir tu codigo en partes reutilizables. Los componentes utilizan la
extension .js o .jsx y se importan con un import de JavaScript
Para definir el término componente citaré la definición de Nicole Sullivan que dice:
“It's a repeating visual pattern, that can be abstracted into an independent snippet of
HTML, CSS and possibly JavaScript.” Nicole Sullivan.
Traduciendo:
Los componentes:
Con lo descrito anteriormente podemos decir que una aplicación reactiva y basada en
componentes nos permiten separar el código y los elementos de la interfaz en pequeñas
piezas independientes y reutilizables que estarán aisladas una de otras, y en lugar de
intentar apuntar y manipular directamente los elementos del DOM cuando la aplicación
reaccioné a las acciones del usuario, ésta actualizará su estado y luego la interfaz se
repintará con los cambios en el estado.
Generalmente el state va a ser un objeto donde cada atributo que tenga este objeto va a ser
cada uno de los estados que quisiéramos controlar, recordar que los estados son los datos
que tiene la aplicación en determinado momento.
Componentes y propiedades
Los componentes permiten separar la interfaz de usuario en piezas independientes,
reutilizables y pensar en cada pieza de forma aislada. Esta página proporciona una
introducción a la idea de los componentes
Conceptualmente, los componentes son como las funciones de JavaScript. Aceptan entradas
arbitrarias (llamadas “props”) y retornan elementos de React que describen lo que debe
aparecer en la pantalla.
Componentes funcionales y de clase
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
Esta función es un componente de React válido porque acepta un solo argumento de objeto
“props” (que proviene de propiedades) con datos y devuelve un elemento de React.
Llamamos a dichos componentes “funcionales” porque literalmente son funciones
JavaScript.
Los dos componentes anteriores son equivalentes desde el punto de vista de React.
Tanto los componentes de función como de clase tienen algunas características adicionales
Renderizando un componente
Anteriormente, sólo encontramos elementos de React que representan las etiquetas del
DOM:
Sin embargo, los elementos también pueden representar componentes definidos por el
usuario:
Nota: Comienza siempre los nombres de componentes con una letra mayúscula.
React trata los componentes que empiezan con letras minúsculas como etiquetas del DOM.
Por ejemplo, <div /> representa una etiqueta div HTML pero <Welcome /> representa un
componente y requiere que Welcome esté definido.
Para saber más sobre el razonamiento detrás de esta convención, puedes consultar JSX en
profundidad.
Composición de componentes
Los componentes pueden referirse a otros componentes en su salida. Esto nos permite
utilizar la misma abstracción de componente para cualquier nivel de detalle. Un botón, un
cuadro de diálogo, un formulario, una pantalla: en aplicaciones de React, todos son
expresados comúnmente como componentes.
Por ejemplo, podemos crear un componente App que renderiza Welcome muchas veces:
function Welcome(props) {
return <h1>Hello, {props.name}</h1>;
}
function App() {
return (
<div>
<Welcome name="Sara" /> <Welcome name="Cahal" /> <Welcome
name="Edite" /> </div>
);
}
Por lo general, las aplicaciones de React nuevas tienen un único componente App en lo más
alto. Sin embargo, si se integra React en una aplicación existente, se podría empezar de
abajo hacia arriba con un pequeño componente como Button y poco a poco trabajar el
camino a la cima de la jerarquía de la vista.
Extracción de componentes
Acepta author (un objeto), text (un string), y date (una fecha) como props, y describe un
comentario en una web de redes sociales.
Este componente puede ser difícil de cambiar debido a todo el anidamiento, y también es
difícil reutilizar partes individuales de él. Vamos a extraer algunos componentes del mismo.
function Avatar(props) {
return (
<img className="Avatar" src={props.user.avatarUrl}
alt={props.user.name} /> );
}
El Avatar no necesita saber que está siendo renderizado dentro de un Comment. Esto es por
lo que le dimos a su propiedad un nombre más genérico: user en vez de author.
Recomendamos nombrar las props desde el punto de vista del componente, en vez de la del
contexto en el que se va a utilizar.
function Comment(props) {
return (
<div className="Comment">
<div className="UserInfo">
<Avatar user={props.author} /> <div className="UserInfo-
name">
{props.author.name}
</div>
</div>
<div className="Comment-text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
function UserInfo(props) {
return (
<div className="UserInfo"> <Avatar user={props.user} />
<div className="UserInfo-name"> {props.user.name} </div>
</div> );
}
function Comment(props) {
return (
<div className="Comment">
<UserInfo user={props.author} /> <div className="Comment-
text">
{props.text}
</div>
<div className="Comment-date">
{formatDate(props.date)}
</div>
</div>
);
}
Extraer componentes puede parecer un trabajo pesado al principio, pero tener una paleta de
componentes reutilizables vale la pena en aplicaciones más grandes. Una buena regla en
general, es que si una parte de su interfaz de usuario se usa varias veces (Button, Panel,
Avatar), o es lo suficientemente compleja por sí misma (App, FeedStory, Comment), es
buen candidato para extraerse en un componente independiente.
Ya sea que declares un componente como una función o como una clase, este nunca debe
modificar sus props. Considera esta función sum :
function sum(a, b) {
return a + b;
}
Tales funciones son llamadas “puras” porque no tratan de cambiar sus entradas, y siempre
devuelven el mismo resultado para las mismas entradas.
Todos los componentes de React deben actuar como funciones puras con respecto a
sus props.
Por supuesto, las interfaces de usuario de las aplicaciones son dinámicas y cambian con el
tiempo. En la siguiente sección, introduciremos un nuevo concepto de “estado”. El estado
le permite a los componentes de React cambiar su salida a lo largo del tiempo en respuesta
a acciones del usuario, respuestas de red y cualquier otra cosa, sin violar esta regla.
CREANDO COMPONENTES
Crear una carpeta llamada components en la carpeta src, dentro crear los componentes que
se requiera con extension jsx. Se pueden crear varios archivos en un componente pero para
mejor legibilidad y organización del codigo se crea un archivo por componente.
La primera letra del nombre del archivo del componente y del componente debe ir en
mayuscula. Cuando se usa vite se usa la extension jsx, si fuese create React App se puede
usar .js o .jsx
React Components
rcc
import React, { Component } from 'react'
rce
import React, { Component } from 'react'
export default $1
rcep
import React, { Component } from 'react'
import PropTypes from 'prop-types'
render() {
return <div>$2</div>
}
}
export default $1
rpc
import React, { PureComponent } from 'react'
rpcp
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
render() {
return <div>$2</div>
}
}
rpce
import React, { PureComponent } from 'react'
import PropTypes from 'prop-types'
rccp
import React, { Component } from 'react'
import PropTypes from 'prop-types'
render() {
return <div>$4</div>
}
}
rfcp
import React from 'react'
import PropTypes from 'prop-types'
function $1(props) {
return <div>$0</div>
}
$1.propTypes = {}
export default $1
rfc
import React from 'react'
rfce
import React from 'react'
function $1() {
return <div>$0</div>
}
export default $1
rafcp
import React from 'react'
import PropTypes from 'prop-types'
$1.propTypes = {}
export default $1
rafc
import React from 'react'
const $1 = () => {
return <div>$0</div>
}
export default $1
rafce
import React from 'react'
const $1 = () => {
return <div>$0</div>
}
export default $1
rmc
import React, { memo } from 'react'
rmcp
import React, { memo } from 'react'
import PropTypes from 'prop-types'
$1.propTypes = {}
export default $1
rcredux
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import { connect } from 'react-redux'
render() {
return <div>$4</div>
}
}
const mapDispatchToProps = {}
reduxmap
const mapStateToProps = state => ({})
const mapDispatchToProps = {}
CSS Plano
Framework CSS
Módulos CSS
Componentes
SASS
Styled Components
Comandos:
@tailwind base;
@tailwinds components;
@tailwinds utilities
El el archive tailwind.config.js se escibe en el arry content los archivos a los que se les va a
estar agregando el css,es decir que archivos que formaran parte de la presentacion del
proyecto
content: ["./index.html",
"./src/**/*.jsx"]
"./src/**/*.jsx"] Esto indica busca en todas las carpetas de src todos los archivos .jsx donde
quier oque esten disponibles las clases de tailwind
En los archivos jsx las clases se agregan con la palabra className, no se usa class ya que
esta es una palabra reservada de javascript, y aunque jsx no es javascript tiene acceso a
todos los metodos y propiedades del lenguaje
HOOKS EN REACT
Los Hooks son funciones que te permiten “enganchar” el estado de React y el ciclo de vida
desde componentes de función. Los hooks no funcionan dentro de las clases — te permiten
usar React sin clases
React proporciona algunos Hooks incorporados como useState. También puedes crear tus
propios Hooks para reutilizar el comportamiento con estado entre diferentes componentes.
Primero veremos los Hooks incorporados.
QUE ES EL STATE?
useState hook para manejar los estados de la aplicacion
El State o estado es basicamente eso; cual es el estado de nuestra aplicación, por ejemplo en
un carrito de conpras el estado se refiere a si el carrito esta vacio o no, que informacion
tiene. En un listado de cliente si se descargo e listado o no, si hubo algun problema, etc.
El Estado es una variable con informacion relevante en nuestra aplicacion de React, algunas
veces el state pertenece a un componente en especifico o algunas veces deseas compartirlo
a lo largo de diferentes componentes.
Al final el state es un destructuring de arreglos
const [cliente,setCliente]=useState({})
const[total,setTotal]=useState(0);
React reacciona en base al state, cada vez que tu state cambia, tu aplicación de React va a
renderizar y actualizarse con esos cambios.
Para modificar el State, se utiliza la funcion que extraemos cuando declaramos el state en
nuestro componente:
La funcion del lado derecho: setCleinte o setTotal , setModal,etc,. Nunca se debe hacer por
asignacion, no se debe asignar el valor de la variable del lado izquierdo por asignacion
IMPLEMENTAR useState
Debe ser declarado en la parte superior del componente, dentro del componente pero antes
del return
EVENTOS DE REACT
La forma en la que React maneja los eventos es muy similar a como lo haca JavaScript de
forma nativa, solo con algunos cambios
SINTAXIS
HTML JSX
<button onclick=”descargarPedidos()”> <button onclick={descargarPedidos()}>
Descargar Pedidos Descargar Pedidos
</button> </button>
HTML
<form onsubmit=”agregarCliente(): return false”>
<button type=”submit>Submit</button>
</form>
JSX
<form onSubmit{handleSubmit}>
<button type=”submit>Añadir Cliente</button>
</form>
Es importante el orden en que se declaran los state, dee ser en el mismo orden en que se
usan en el documento, por ejemplo conservar el orden de los campos del formulario
PROPS EN REACT
Es State o funciones que creas en tus componentes solo estaran disponibles en ese
componente.
Una forma de evitar duplicar codigo y reutilizar esas variables, state, estado o funciones en
otros componentes es por medio de Props o propiedades.
Los Props se pasan del padre al hijo, nunca se pasan del hijo al padre.
Conceptualmente, los componentes son como las funciones de JavaScript. Aceptan datos de
entrada (llamados props) y returnan elementos de React que describen lo que debería
aparecer en la pantalla.
Las props son la colección de datos que un componente recibe del contenedor padre, y que
pueden usarse para definir los elementos de React que retornará el componente.
En JSX, las props se ven como los atributos de los elementos HTML:
Estas props pueden recibir un string o el resultado de una expresión de JavaScript, usando
la sintaxis de llaves:
SINTAXIS
<Header
nombreProp={datos o funciones}
//LA parte de la izquierda es el nombre del prop, la parte del lado derecho es la variable o
funcion del state o una funcion en caso de haberla creado
/>
Otro Ejemplo
<Header
numeros={1}
clientes={clientes}
isAdmin={false}
setClientes={setClientes}
titulo=”Tienda Virtual”
/>
Cada nivel de componentes debera tomar y pasar el Prop hacia otros componentes,
tecnologias como Redux o Context evitan tener que hacerlo de esta forma.
En la parte superiro del archivo App.jsx se coloca import {useState} from ‘react’
setArreglo es el modificador del arreglo, ya que las props son inmutables no se pueden
hacer asignaciones o modificaciones sobre ellas directamente sino a traves de setArreglo
donde Arreglo es el nombre de la propiedad, variable, objeto o arreglo.
Se inicializa en vacio.
En la parte superior del componente donde se asignan los props se coloca la palabra
reservada props como parametro de la funcion componente. Si no se quieren pasar todos los
props se aplica destructuring del objeto como parametro y asi se accede a cada prop
function Header(props) {
console.log(props);
return (
<>
<h1 className="font-black text-5xl text-center md:w-2/3 mx-auto">Seguimiento
Pacientes {""}<span className="text-indigo-600">Veterinaria</span></h1>
</>
)
}
Otro Ejemplo
function Header({numeros,isAdmin}) {
console.log(numeros);
console.log(isAdmin);
return (
<>
<h1 className="font-black text-5xl text-center md:w-2/3 mx-auto">Seguimiento
Pacientes {""}<span className="text-indigo-600">Veterinaria</span></h1>
</>
)
}
Ya que los props solo se pasan del padre al hijo y no viceversa, para pasar valores del hijo
al padre se hace lo siguiente:
function App() {
const tomaUnValor=(valor)=>{
console.log(valor);
}
return (
<div className="container mx-auto mt-20">
<Header
tomaUnValor={tomaUnValor}
/>
<div className="mt-12 md:flex">
<Formulario
/>
<ListadoPacientes />
</div>
</div>
)
}
Children es una palabra reservada en react que hace referencia a todo lo que le pases en un
componente.
Cuando se trabaja con props hay que pasarlos por niveles, desde el padre4 hasta el nivel del
componente donde se necesite.
HELPERS O UTILS
Estos son archivos con funciones utilitarias, se crea una carpeta llamda helpers o utils y
dentro van los archivos con funciones utilitarias y son exension js.
HOOK useEffect
Usos de useEffect
También es posible a este useEffect pasarle una dependencia de esa forma va a estar
escuchando por los cambios que sucedan en una variable o en tu state y puede actualizar el
componente cuando ese cambio suceda
Es una funcion que toma un callback como argumento y luego una coma y un arreglo de
dependencias que es el state a escuchar. Si el arreglo de dependencias esta vacio solo se
escucha 1 vez
Sintaxis
useEffect(()=>{
console.log(‘El Componente esta Listo’);
},[uy])
//El arreglo vacio al terminar la arrow function son las dependencias, ese es el valor que va
a estar revisando cuendo cambie, y si cambia realiza un re-render.
Se pueden tener multiples useEffect en el codigo, asi como pueden existrir multiples
usestate. Si las dependencias estan vacias solo se va a ejecutar 1 vez, si las dependencias
tienen un valor se va a ejecutar cada vez que ese valor cambie.
IMÁGENES EN REACT
//Asi se importa
import comida01 from '../images/comida-01.jpg'
//Asi se usa
<img src={comida01} alt=""/>
Ejemplo si se va a buscar una imagen dependiendo de la categoria, es decir se crea un
diccionario de imágenes
const diccionarioIconos = {
ahorro : IconoAhorro,
comida : IconoComida,
casa : IconoCasa,
gastos : IconoGastos,
ocio : IconoOcio,
salud : IconoSalud,
suscripciones : IconoSuscripciones
}
Para desplegar un proyecto corremos el comando npm run build . Esto crea una carpeta
llamada buid donde estaran los archivos de produccion del proyecto.
Y se setea o cambia cuando hay un cambio en el value del input, es decir si el usuario teclea
otra cosa, inicialmente el estado de estos props estan como vacio.
useEffect(()=>{
if(Object.keys(paciente).length>0){
setNombre(paciente.nombre);
setPropietario(paciente.propietario);
setEmail(paciente.email);
setFecha(paciente.fecha);
setSintomas(paciente.sintomas);
}
},[paciente])
En este caso useEffect esta siempre monitoreando el objeto paciente, que se diferencia del
arreglo paceintes porque pacientes es un arreglo lleno de una colección de objetos paciente,
este paciente es el que esta en memoria, que cambia o se setea cuando en el componete
paciente se presiona el boton editar:
al darle editar se regresa hacia App.jsx y pasa hacia formulario porque tenemos un props
paciente en formulario , en formulario se extrae en los props que se pasan como argumento
en el componente funcional formulario el useEffect detecta cuando ese cambio surja y eso
es lo que se va a los inputs del formulario por medio del
setNombre(paciente.nombre);
setPropietario(paciente.propietario);
setEmail(paciente.email);
setFecha(paciente.fecha);
setSintomas(paciente.sintomas);
Cambiar el value del boton submit del formulario
en handleSubmit:
Aquí se realizan las validaciones al presionar submit. El objetoPaciente es el objeto en
memoria de lo que se elee en el formulario, pero a su vez viene un props paciente en
memoria que es el estado paciente que se alamacena al presionar editar paciente.
Se verifica si el objeto props paciente tiene id, de seta asi quiere decir que es una edicion,
en caso contrario es un nuevo registro. objetoPaciente no tiene id, se le genera en caso de
sser un nuevo registro.
Cuando se esta actualizando el paciente si tiene un id, pero objetoPaciente que es el state de
la recoleccion de los datos del formulario no tiene ningun id, en este caso asignamos
objetoPaciente.id=paciente.id
nos interesa agregar objetoPaciente con setPaciente , para eso se genera un nuevo arreglo
con .map, en donde se itera sobre todos los pacientes(el arreglo de objetos que contiene
todos los pacientes y es el props pacientes) verificando , dentro de este map se verifica si el
id del objeto del state de los datos del formulario es igual al id del pcaiente del state que se
obtuvo al presionar el boton editar es igual, de sera asi retorno el objeto del state de los
datos del formulario que es la actualizacion, en caso contrario retornar el objeto tal cual
como esta que es lo que esta dentro de paciente que es el state que tiene los datos
almacenado.
const pacientesActualizados=pacientes.map(pacienteState=>{
pacienteState.id=paciente.id ?objetoPaciente :pacienteState
})
luego de actualizar el state pacientes hay que limpiarlo, para esto le enviamos desde el
App.jsx el state statePaciente al formulario para extraerlo en el formulario via props y
tenerlo disponible e inicializarlo
NOTAS: En el evento se colocan los state o las funciones de esta forma cuando se requiere
mandar a llamra un parametro:
onClick={()=>setPaciente(paciente)}
No se hace esto:
onClick={sepPaciente()} porque manda a llamar la funcion inmediatamente
onClick={handleEliminar} , esto permite que se espere hasta que suceda el evento click
Luego de la validacion de los datos de lgasto se llama una funcion guardar gastos, esta
funcion va aestar en el compomente principal app.jsx, ya que la logica sera pasar los
parametros de esa funcion desde el formualrio donde se recogen. El formulario recolecta
nobre,cantidad y categoria y se envia como un objeto a la funcion guardarGastos en el
comoponente principal, el desarrollo de esta fiuncion lo que hace es tomar ese objeto y
setear el state de gastos creando una copia ue anexe al state de gastos el objeto gasto
recolectado del formulario
VARIOS
leer de un input en teimpo real y guardarlo en prop:
onChange={e=> setValorProp=(e.target.value)}
STYLED COMPONENTS
Styled Components es una de las librerías más populares para inyectar CSS en JavaScript.
No es específica para React ni para ningún otro framework. La puedes utilizar junto con
cualquier framework basado en componentes.
Utiliza template literals u objetos para crear componentes con estilo que puedes usar
directamente en tu código.
Los tratas igual que a los componentes que ya conoces por lo que puedes pasar props, poner
componentes dentro de otros componentes, darle un id, ser reutilizados, entre otras.
Para dar estilo puedes usar CSS y otras funcionalidades adicionales popularizadas por pre-
procesadores como Sass.Styled Components añade una clase única a cada componente para
evitar problemas de especificidad. Además, esto asegura que el buscador solo cargue el
código necesario para cada página de tu aplicación.
Instalación
CUSTOM HOOKS
Una de las razones para crear nuestros propios Hooks es para poder reutilizar una funcion .
Una gran ventaja de crear custom hooks es incorporar el state y todas las funciones de react
y mantener el valor de una funcion de forma persistente
Tu codigo personalizado tendra todas las ventajas de React como son: state , effects,
integrar otros hooks y el performance, un hook sera reurilizavle en otros proyectos y en
otros lugares de la pagina
COMO CREAR NUESTROS PROPIOS HOOKS En src se crea una carpeta nueva llamada
hooks, dentro de esta se crean los archivos hooks que queremos crear. Los archivos hooks
por convencion deben inciar su nombre con la palabra use por ejemplo
useSelectMonedas.jsx, la sintaxis puede ser la misma que la que se usa al crear un
componente, con la diferencia de que no tienen el return tradicional de los componentes, un
hook va a retornar ya sea un objeto o un arreglo tal como lo hace el hook de useState
Ejemplo:
Para mandarlo a llamar se extrae (en el componente dond se usa) la funcion del hook, en
este caso SelectMonedas y mandarla a llamar
return [SelectMonedas]
}
Al hacer la llamada del hook en el componente se puede hacer como si fuese otro
componente mas:
<SelectMonedas /> //y en este caso si va dentro del return del componente
USO DE STATE EN LOS CUSTOM HOOK
>Selecciona Tu moneda</option>
{opciones.map(opcion=>(
<option
key={opcion.id}
value={opcion.id}
>{opcion.nombre}</option>
))}
</Select>
</>
)
return [state,SelectMonedas]
}
API
API = Application Programming Interface
Funciones, metodos que ofrece una librería para ser utilizada por otro software como una
capa de abstraccion
Una API pone a disposicion recursos que estan alojados en otro servidor o base de Datos
Al ser React una librería que corre en el lado del cliente, no puede consultar una base de
datos, por lo tanto una API es la forma de obtener datos de un servidor
La API puede ser creada en cualquier lenguaje o framework : Python, java, Net
core, Express, Node JS, Laravel, PHP. Para ello deben entregar una respuesta de tipo Json.
const url=”url”
const consultarAPI=async()=>{
const respuesta=await fetch(url)
const resultado = await respuesta.json();
}
consultarAPI();
ROUTING
Con una librería de Routing se pueden tener diferentes URL´S y mostrar diferentes
componentes, asi como restringir acceso a ciertas páginas.
Es una libreria para crear aplicaciones con Routing(diferentes URL´s) . Al tener diferentes
páginas tendremos un mejor orden en nuestro código, y podemos seguir reutilizando
componentes y más
escribir en main.jsx
import {createBrowserRouter, RouterProvider} from ‘react-router-dom
Notas:
createBrowserRouter permite definer un browser por medio de objetos, esto permite
definir todas las rutas por medio de un objeto principal
const router=createBrowserRouter([
{
path: ‘/’, //Esto indica que es la página de inicio, puede ser /tienda, etc
element: <h1>Inicio </h1>
}
])
en algunos ejemplos tambien definen una carpeta o un archivo nuevo llamado router,
tambien se puede hacer de esa forma.
createBrowserrouter toma un arreglo en donde se van definir diferentes rutas por medio de
un objeto
path es la forma en la que se van definiendo las diferentes URL´s, e pueden tener un path
para un nosostros, un path para una tienda
LAYOUT
El layout es el diseño de plantilla que se repite en todas las paginas, es como el patron y
dentro de el va el contenido de los componentes que se renderrizan de forma dinamica, este
renderizado dinamico se logra a traves del componente especial <Outlet /> que es propio de
React Router Dom
en este archivo se crea el componente con el short code rfce de vite, el cual crea un
componente como una funcion declarada
const router=createBrowserRouter([
{
path:'/',
element:<Layout />
}
])
Para colcoar el contenido dinamico dentro de la plantilla o layout, este se renderiza
definiendo un outlet, se importa como un componente dentro del componente Layout, este
outlet actua como un place holder, como un contenedor dinamico y va a mantener la
apariencia en cada uno de los componentes sin embargo le permite con este outlet que el
contenido que se le pase donde se decida utilizar este layout se va a inyectar a partir de alli,
digamos que se le deja espacio reservado para que en diferentes paginas, diferentes routings
se le diga que se quiere mostrar en esa parte y lo que esta por fuera del Outlet se renderiza
en todos los demas componentes.
function Layout() {
return (
<div>
<h1>CRM-React-Router-DOM</h1>
<Outlet />
</div>
)
}
E main.jsx
const router=createBrowserRouter([
{
path:'/',
element:<Layout />,
children: [
{
path:'/nosotros',
element:<h1>Nosotros</h1>
}
]
}
])
Asi como se tiene como element elementos html tambien se puede tener un componente
para que Outlet lo tome
import './index.css'
import Layout from './components/Layout'
import NuevosCliente from './pages/NuevosCliente'
const router=createBrowserRouter([
{
path:'/',
element:<Layout />,
children: [
{
path:'/clientes/nuevo',
element:<NuevosCliente/>
}
]
}
Se le esta diciendo con index:true que esta es la pagina principal raiz que se muestra, no se
ele incluye path porque no lo requiere ya que con index:true se le dice que es la ruta raiz
Outlet es un componente reservado para que el contenido de os otros componentes que son
hijos que estan definidos en children se inyecten es esa parte.
Se usa el componente Link, el cual debe importarse de react-router-dom al igual que Outlet
Para hacerlo de una forma optimizada se usa el componente Link , esta es la sintaxis
<Link to=”/”>Clientes </Link>
<Link to=”/clientes/nuevo”>Clientes </Link>
Al inspeccionar esta pagina en ejecucion, siguen siendo enlaces. Link crea una capa de
abstraccion para hacerlo más optimizado
Existe otro componente que hace practicamente lo mismo y es NavLink, ambos estan
especialmente diseñados para crear barras de navegacion y permitirle al usuario navegar a
lo largo de diferentes páginas
RESALTAR LA PÁGINA ACTUAL
useLocation
key: Id unico que se genera de forma dinamica y cambia cada vez que se recarga la página
Ejemplo
LOADER
Creando un loader
Usualmente existen paginas donde los datos del contenido que se va a renderizar vienen de
una consulta a una API o una Base de Datos que se guardan en un state, usualmente para
esto se usa un useEffect que vigila que ese componente que el state que contiene esos datos
este listo y de esa forma se carga la informacion.
En la version 6.4 y adelante se usa una funcion llamada loader y no se usa useEffect para
este caso, este loader es una funcion que se crea en el componente donde queremos que se
cargue, en este ejemplo en particular estara en index, desde index se exporta y en main.jsx
se vuelve a iportar usando la declaracion
import Index, {loader as clientesLoader} from './pages/Index'
Loader es una function que se va a ejecutar cuando el componente cargue y es ideal para
cargar un state o para consultar alguna API y obtener algun resultado que se quiera mostrar
en un componente, m este loader siempre debe retornar algo, sino no va a funcionar, puede
retornar una funcion, un arreglo o un string, este retorno usualmente siempre va ser el state
del componente donde esta.
Luego para volverlo a traer al index, para ello en el objeto children del router se coloca
loader: clientesLoader
const router=createBrowserRouter([
{
path:'/',
element:<Layout />,
children: [
{
index:true,
element:<Index/>,
loader: clientesLoader
},
{
path:'/clientes/nuevo',
element:<NuevosCliente/>
}
]
}
])
useNavigate
Es un hook que se usa para navegar de forma programada, es decir,se usa para que en caso
de que elusuario presione en un boton, poder navergar hacia otra página, no en un enlace
sino en un boton, y tambien despues de haber pasado alguna validadción.
Se usa de la siguiente forma
const navigate=useNavigate()
De esta foma nos lleva a la direccion que se le indique como parametro entre los parentesis
onClick={()=>navigate('/') }>Volver</button>
onClick={()=>navigate(-1) }>Volver</button>
</div>
Existe otra forma de redirecciona r que se llama redirect, epero esre es mejor usarlos en
loaders y en actions.
Uso de action
Se realiza a traves de un componente incluido en react router dom llamado Form con F
mayuscula y una funcion que es el action, tien ciertas reglas y debe nombrarse de ciertas
formas
<Form
method=”post”
action>
</Form>
Para hacerle saber al componente Form que tenemos una funcion action que queremos
mandar a llamr una vez se presione el submit se hace lo siguiente:
{
path:'/clientes/nuevo',
element:<NuevosCliente/>,
action:nuevoClienteAction
}
formData
La funcion action que esta asociada a un formulario requiere un request como parametro, es
una peticion que se esta realizando hacia el action. En el protptype del request se encuentr
algo llamado formData, en las peticiones Ajax o fetch se colocan los datos del formulario
en un formData y luego enviarla a un servidor. Es la forma en la que se puede acceder a la
informacion de un formulario.
Esta funcion action debe realizarce de forma asincrona porque el request puede tardar un
rato en procesar y obtener los datos del formData.
Parta obtener los datos del formulario que estan en el formData se debe usar algunos
metodos que estan dentro del formData tales como get o fromEntries
Al colocarle un spread operator a un formData si permite leer sus datos, este snippet
permite debugear un formData
const datos=Object.fromEntries(formData);
console.log(datos)
const errores=[]
if (Object.Values(datos).includes(‘’)){
errores.push(‘Todos los campos deben estar llenos)
return errores
}
}
return errores permite que el action retorne los errores. Ahora ya estan listos para pasarse
pero debemos buscar obtenerlos para pasarlos al componente . Al igual que con el loader
existe un hook para usar y se llama useActionDatta.
function NuevosCliente() {
const errores= useActionData();
console.log(errores)
Asi ya aparecen desde el componente y se pueden tomar como datos para mostrar en
cuaquier lugar del componente.
en esta expresion se usa el optional chaining ,permite leer el valor de una propiedad ubicada
dentro de una cadena de objetos conectados sin tener que validar expresamente que cada
referencia en la cadena sea válidaEl operador de encadenamiento opcional proporciona una
forma de simplificar el acceso a los valores a través de objetos conectados cuando es
posible que una referencia o función sea undefined o null.
con esa instruciion se esta diciendo si hay algo en errores porque existe la
propiedad .length, eso quiere decir que hay algo, luego el && es un perador de corto
circuito que indica que si la consicion de la izquierda se cumple entonces se manda a llamar
la de la derecha.
Como puede ser que haya multiples eoorres se le coloca un Key llamado i que es el indice,
la posicion que tendria ese error en el arreglo, ya que este arrglo contendra varios errores de
otros action o vlaidaciones, usualmente no se debe colocar el key con el indice, sobre todo
cuando son datos que pueden cambiar , como por ejemplo clientes ue se pueden eliminar o
agregar mas, aquí no se recomienda hacerlo
useloaderData y useActionData
cuanod usra uno o el otro? esLoaderData se usa cuando se quiera obtener el resultado
dei¡un loadar y useActionData cuendo se queira obtener el resultado de un action , el action
esta vinculado a envios de formualrios.
Debe responder a los Request HTTP: GET, POST, PUT, PATCH, DELETE
Tiene una forma ordenana y estructurada de poner a disposicion los recursosos
VERBOS HTTP
GET : Es utilizado para obtener registros de una base de datos o una API
POST: Es usado para Enviar datos al servidor o para creacion de registros
PUT/ PATCH: Es usado para la actualizacion de registros.
DELETE: Es usado para eliminar registros.
Eliminar un cliente
DELETE/clientes/8
{
"posts": [
{ "id": 1, "title": "json-server", "author": "typicode" }
],
"comments": [
{ "id": 1, "body": "some comment", "postId": 1 }
],
"profile": { "name": "typicode" }
}
Ejemplo :
{"clientes" : [
{
" id": 1,
"nombre": "'Juan'",
"telefono": 102013313,
"email": "juan@juan.com",
"empresa": "'Codigo Con Juan'"
},
{
"id": 2,
"nombre": "'Karen'",
"telefono": 138198313,
"email": "karen@juan.com",
" empresa": "'Codigo Con Juan'"
},
{
"id": 3,
"nombre": "'Josue'",
"telefono": 31983913,
"email": "josue@juan.com",
"empresa": "'Codigo Con Juan'"
},
{
"id": 4,
"nombre": "'Miguel'",
"telefono": 319381983,
"email": "miguel@juan.com",
"empresa": "'Codigo Con Juan'"
},
{
"id": 5,
"nombre": "'Pedro'",
"telefono": 1398198938,
"email": "pedro@juan.com",
"empresa": "'Codigo Con Juan'"
}
]
}
Crear una carpeta en src llamada data, dentro de esta colocar un archivo, en este caso se
llama clientes.jsx, este archivo va a cntener los datosrealcionados con el cliente y las
consultas CRUD que se hagan .
Se exporta para poder pasar la consulta al componente donde esta la funcion loader , se
defime una funcion async ya que se trabaja con request http y estas pueden tardar en
responder.
como se vaa hacer un fetch se requiere una url, esta se va a guardar en una variable de
entorno, una variable de entorno es una variable que en elentrono de desarrollo puede tener
un valor y en el entrono de produccion tiene un valor diferente.
Cada framework o herramienta que se escoja para crear proyectos tiene una forma de
definir y administrar las variables de entrono. En Vite se hace de la siguiente forma:
Se crea fuera de la crpeta src un archivo llamado .env, dentro de este archivo se escribe lo
siguiente:
VITE_API_URL=http://localhost:3000/clientes
Como se creo un archivo nuevo, se termina la sesion del servidor con ctrl c y se vuelve a
arrancar
En el componente donde esta el loader que es donde se usan esots datos , se importa la
funcion obtenerClientes y cuando cargue la funcion loader se manda a llamar.
En /data/clientes
en ./pages/index.jsx
MANEJAR ERRORES
en main.jsx
const router=createBrowserRouter([
{
path:'/',
element:<Layout />,
children: [
{
index:true,
element:<Index/>,
loader: clientesLoader,
errorElement:<ErrorPage />
Este Error element puede contener un componente, para esto se crea un componente llamdo
ErrorPage y al igual que el loader requiere un hook que se llama useRouteError que se usa
para pasar el contenido del error al componente y a su vez a la route(el objeto del arreglo
children) que lo contiene
en componente ErrorPage.jsx
NOTAS: react router dom utiliza formdata para almecenar lo que el usuario ha ingresado en
este formulario.
Siguiente paso: como ya se tiene el servicio en la carpeta data, con el archivo clientes, aquí
se genera una funcion encargada de agregarClientes , esta funcion es async porque se usa
fetch API y recibe como parametro los datos que vienen del componente nuevoCliente a
traves del action y el uso del formData.
Siguiente paso abrir el archivo nuevoCliente e importar esa funcion del servicio cliente (en
este caso el servicio cliente es el encargado de manejar las acciones CRUD sobre la API o
Base de Datos) que se acaba de crear.
El try catch va a intentar realizar la accion y en case de que se produzca un error ejecuta el
catchy va a mosrtar un mensaje de error parapoderlo debuggear
En el fetch se usa la url guardada een la variable de entorno , este fetch requeiere de otros
parametros ya que el request es POST
Todo action y loader debe devolver un return, en este caso le retornamos unredirect, en este
caso par el redirect se usa un redirect que viene de react router dom, es por eso que hay que
importarlo junto con los hooks.
Nota importante:
Para redireccionar:
EDICION
en el path usamos una sintaxis especial que inicia con 2 puntos y se le puede asignar a la
variable que sigue a los 2 puntos el nombre que se desee pero es recomendable colocarle un
nombre relacionado con el campo clave que se esta trayendo de la base de datos o API, en
este caso se le coloco clienteId, este nombre de variable es el que react router dom va a
generar en la url
Se crea un componente llamado EditarCliente que va a ser el valor del element, es decitr es
lo que se va a renderizar cuando se cree la url de editar, este componente en este caso se
llama EditarCliente.
Para ir a esa pagina la unica forma de hacerlo es presionando el boton editar del listado de
cliente, para redireccionar con este boton se usa navigate.
Esto nos va a permitir navegar de forma programada. navigate lleva un parametro, en este
caso la variable que se le va a pasar en un id
<button type="button"
className="text-blue-600 hover:text-blue-700 uppercase font-bold text-xs"
onClick={()=>navigate(`/clientes/${id}/editar`)}>
Editar
</button>
La logica es Tomar el id del cliente del parametro params que se define en el loader, este id
de cliente es el que agregaremos al resquest GET/clientes/id que se hace mediante la
peticion fetch a la Api, luego de recibir estos datos los mismos se cargan al formulario en
automatico
Paso 1 Obtener los datos asociados al id que viene en la url
Definir una funcion que realice el request de GET mediante fetch a la API
export async function obtenerCliente(id){
const respuesta = await fetch(`import.meta.env.VITE_API_URL/${id}`)
const resultado = await respuesta.json()
return resultado
Importar esa función en el componente editarCliente y hacer uso de ella en el loader para
obtener los datos asociados a ese id de cliente
console.log( cliente)
return cliente
}
En react router dom en el loader se pueden hacer las comporbaciones de datos existentes o
validos.
if(Object.values(cliente)===0){
throw new Response('',{
status:404,
statusText:'Cliente no encontrado'
})
}
el throw new Response() lleva los aprametros status: que define el tipo de error, en este
caso es el 404 por url o pagina no encontrada y el statusText es el texto personalizado que
queremos que vea el usuario.
Ahora al children de editar hay que informarle que hay un error element, eso lo hacemos en
el main.jsx en la descripcion del objeto children
El throw new Response detiene la ejeccuion del cogido y no se retorna el cliente sino la
pagina de error.
Logica
Para llevar a cabo la accion de actualizar un registro con action es muy parecido a incluir
un nuevo registro, con la diferencia que se debe acceder al id del registro a editar
Primero registrar el action en el componente editarCliente, este action realiza la toma de los
campos del formulario por medio de
const formData=await request.formData();
const datos=Object.fromEntries(formData);
luego realiza unas validaciones de los campos de entrada y luego de pasar las validaciones
se hace llamado a una funcion que debe estar insluida en el servicio clientes.js que esel
archivo que contiene todas las instrucciones de los request de la aplicación, esta funcion es
actualizar cliente, esta funcion va a tomar como parametros request y params , params nos
va a decir que cliente necesitamos actualizar.
En el await se manda a llamar la funcion actualizarCliente que se debio definir en el
servicio clientes.js
Hay que recordar añadir el action en el main.jsx y luego pasarlo al children de editarcliente
en el campo action:
en el children:
{
path:'/clientes/:clienteId/editar',
element:<EditarCliente />,
loader :editarClienteLoader,
action:editarClienteAction,
errorElement:<ErrorPage />
}
en clientes.js
en la llamada en el componente:
await actualizarCliente(params.clienteId,datos)
Este es un hook que nos permite recuperar la parte del action y useLoaderData nos permite
recuperar la parte del loader
npx create-strapi-app@latest
Aquí se crean las tablas, cada collection type es una tabla a la que se le pueden agregar
diversos campos
CONTENT MANAGER
Esto es para llenar los datos de las tablas
La diferencia entre un single y un collection es que este solo te permite tener 1 solo
elemento de ese tipo, es decir no se puede crear un colección de datos.
REMIX RUN
Es hecho por los creadores de react router dom, se utilizan mucho cosas como actions y
loaders.
Ventajas de Remix
Cero configuracion
Buen performance y esta optimizado para SEO
Routing incluido
Manejo de Peticiones HTTP similar a React router DOM
El codigo sigue siendo React: componentes, hooks, etc
Su sitio es remix.run
npx create-remix@latest
En remix no existe la carpeta src, lo que se renderiza en pantalla viene de la carpeta app.
en la carpeta route esta el archivo index.js que es el que renderiza los componentes. En
remix la carpeta donde se va a escribir la mayor parte del codigo es en la carpeta app, a
diferencia de vite que se hacia en la carpeta src.
Tiene una carpeta llamada cache para que cada vez que estemso construyendo el sitio no
sea tan lento.
La carpeta build guarda toda la informacion del proyecto, en public hay otra carpeta build
donde se puede guardar imágenes y archivos estaticos
Algo que tiene remix a diferencia de vite, es que es muy encillo agregar hojas de estilo
para ciertas paginas o modificar todo lo que esta en el head.
para esto se crea un function que se puede llamar Document o Layout y dentro de esta
funcion estara la estructura semantica del html, a esta funcion se le pasa como props
children, de esta forma cuando se incluya en el componente App lo que este como children
se va a renderizar todo lo que se le pase alli:
function Document({children}){
return (
<html lang ="es">
<head>
<title>GuitarLA-remix</title>
<body>
{children}
</body>
</head>
</html>
)
}
Para agregar informacion meta u hojas de estilo se debe exportar una funcion , en el
momento que se exporta va a estar automaticamente disponible en esa ruta
Para poder renderizar estos datos y que se agreguen la meta del componente Document es
necesario importar un componente especial de remix
import {
Meta
} from '@remix-run/react'
export function meta() {
return (
[{
charset: 'utf-8',
title: 'GuitarLA - Remix',
viewport: "width=device-width,initial-scale=1"
}]
)
}
Se crea una hoja de estilos css, se puede crear una carpeta llamada styles dentro de app y
alli colocar las hojas de estilos. se importa como se importa un archivo de estilos en react,
se crea una funcion export nombrada que se llame links, se importa el componente especial
de remix Links, se coloca el componente links despues del componente meta.
import {
Meta,
Links
} from '@remix-run/react'
import styles from './styles/index.css'
function Document({children}){
return (
<html lang ="es">
<head>
<Meta/>
<Links/>
<body>
{children}
</body>
</head>
</html>
)
}
Estas hojas de estilos del componente Links en root se van a cargar en todas las paginas y
em¡n todos los componentes, si se queiren tener hojas de estilos mas pequeñas y mas
particulares se puede exportar esa misma funcion links en diferentes componentes
Ests funcion de meta solo funciona en las paginas definidas en la carpeta routes, no
funciona para los componentes, lo mismo siucede con la funcion links que es para agregar
hojas de estilos y enlacves externos.
OUTLET EN REMIX
Tanto remix como next.js tienen un sistema basado en rutas. Para esto se crea una carpeta
routes dentro de la carpeta app, debe ser asi, porque asi lo requiere remix. Dentro de esta se
crean las rutas o archivos de los cuales se compone nuestra aplicación web. El nombre de
los archivos .jsx debe ser en minuscula porque remix crea automaticamene esa url y las url
son en minuscula. La funcion componente dentro de ese archivo si debe estar escrita en
mayuscula ya que esa es la convencion de React.
En remix para inyectar contenido en otro componente se usa outlet igual que en react
router dom, esto para que el contenido de otro componente se inyecte automaticamente en
el componente App que esta demtro del arcchivo root.jsx
Para esto se importa outlet en el archivo root.jsx junto con meta, links, etc.
El siguiente paso es colocar ese aoutlet dentro del componente Document que esta dentro
de la funcion componente App, ahora ese Componente Outlet seria el children que va
dentro del body que estadentro de Document
function Document({children}){
return (
<html lang ="es">
<head>
<Meta/>
<Links/>
<body>
{children}
</body>
</head>
</html>
)
}
Importante recordar que lo que este dentro de la carpeta routes es lo que se va a inyectar en
el outlet del componente app que esta dentro del archivo root.jsx
Si de desea tener una carpeta admin dentro de routes, este admin seria un subdominio y el a
su vez puede tener un index.jsx y la manerade acceder es la siguiente:
nombredominio/admin/index
Si se quiere crear un header que este presente en todas las paginas se jace lo siguiente:
function Document({children}){
return (
<html lang ="es">
<head>
<Meta/>
<Links/>
<body>
<Header/>
{children}
</body>
</head>
</html>
)
}
Existe un alias para escribir las rutas de importacion, sualmente se importan las rutas
siguiendo estos enlaces ‘./styles/’ o ‘../components/’, etc, ela alias ~esta definido em el
archivo tsconfig.json en la llave paths
"paths": {
"~/*": ["./app/*"]
}
Esto quiere decir que el carácter ~se refiere a la ruta “./app/*”, es decir todo lo que esta
dentro de app.
Para agregar los enlaces se usara el componente <Link to=”/ruta”> </Link>, se importa
Links de @remix-run/react
function Header() {
return (
<header className="header">
<div className="contenedro barra">
<div className="logo">
</div>
<nav className="navegacion">
<Link to="/"> Inicio</Link>
<Link to="/tienda"> Tienda</Link>
<Link to="/nosotros"> Nosotros</Link>
<Link to="/blog"> Blog</Link>
</nav>
</div>
</header>
)
}
Importarla como si fuse un componente, la carpeta de las imágenes debe estar en la carpeta
public, esta carpeta tiene el contenido estatico del sitio web.
key: Id unico que se genera de forma dinamica y cambia cada vez que se recarga la página
si se requiere que alguna pagina tenhga informacion meta o codigo css especifica se debe
crear una funcion meta en esa pagina donde se requiere esta informacion personalizada
}
]
}
Esto no elimina las hojas de estilo importadas en root.jsx, solo le añade a nosostros su
propia hoja de estilos.
la funcion meta si sibre escribe la informacion que se coloco en root, ya que por documento
solo puede existir 1 titulo, 1 descripcion, etc.
el atributo rel preload le dice al navegador tan pronto cargues el html, carga determnada
imagen o video porque puede ser muy pesado y debe comenzar a cargar lo antes
posible,esto se coloca en la funcion links
Ejemplo
{
rel:'preload',
href: imagen,
as: 'image'
}
La ventaja de tener una funcion links dentro de un componente es que si ese componente o
pagina se elimina es mas facileliminar el codigo css vinculado a el.
CONSUMIR EL BACKEND DE STRAPI CON REMIX RUN
Remix Run al igual que react router dom hace uso de loader para obtener informacion de la
API y action para enviar informacion a la api, a diferencia de router dom, con remix no se
necesita enviar el loader al main o en este caso el root ya que al exportarlo directamente en
el archivo componente donde se define se manda a llamar en automatico, no se tiene que
asociar ya que remix run corre en el servidor.
Para consumir esta API de strapi se realiza un fetch desde la funcion loader. Es
conveniente definir la url de la API en una variable de entorno. El archivo .env se crea en la
raiz del proyecto. Se define entonces en .env API_URL= http://127.0.0.1:1337
Existe otra forma de realizar la consulta en la API y es creando un archivo modelo, como
en el patron MVC, este archivo modelo le dice a remix que la consulta se realiza en el
servidor. Par esto se hace lo siguiente:
Se crea una carpeta llamada preferiblemente models, en la carpeta app. Destro de esta
carpeta se crea un archivo llamado nombreRelacionadoApi.server.js al colocarlo en .server
le estamos diciendo a remix que este archivo solo debe ejecutarse en la parte del servidor,
en ese archivo se coloca la funcion que realiz la consulta fetch y luego esta funcion es
importada y llamada en la pagina donde se deben mostrarlos datos de la consulta.
return guitarras
}
Consumir una API desde el servidor en lugar de hacerlo directamente desde el cliente tiene
varias ventajas. Aquí te menciono algunas de ellas:
Seguridad: Al consumir una API desde el servidor, puedes mantener tus claves de API y
otros datos sensibles ocultos del cliente. Esto evita que los usuarios finales tengan acceso
directo a información confidencial que podría ser utilizada de manera inapropiada.
Ocultar la complejidad de la API: Si la API que estás consumiendo tiene una estructura
compleja o una interfaz poco amigable, puedes utilizar el servidor para abstraer esa
complejidad y proporcionar una interfaz más simple y fácil de usar para los clientes. El
servidor puede procesar y transformar los datos de la API según sea necesario antes de
enviarlos al cliente.
Evitar problemas de CORS: Al realizar solicitudes desde el servidor en lugar del cliente,
puedes evitar los problemas de política de mismo origen (CORS) que pueden surgir al
hacer solicitudes directas desde el navegador. El servidor actúa como intermediario y puede
realizar solicitudes a otras APIs sin restricciones de CORS.
En resumen, consumir una API desde el servidor en lugar del cliente brinda más control,
seguridad y flexibilidad. Puedes implementar lógica adicional, optimizar el rendimiento y
proporcionar una experiencia de usuario más segura y eficiente. Sin embargo, también
puede agregar complejidad adicional al desarrollo y requerir más recursos de
infraestructura. La elección entre consumir una API desde el servidor o desde el cliente
depende del contexto específico de tu aplicación y tus requisitos.
OBSERVACIONS DE CSS
Cuando se tiene mucho contenido en un parrafo se puede colocar la siguiente sintaxis css
para mover el contenido hacia arriba.
.guitarra .descripcion{
display:-webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
overflow: hidden;
}
Alli se puede ver que apunta auna ruta /guitarras y lo que viene despues /${url}es el
atributo url unico de ruta para acceder a cada guitarra.
Para lograr esto en remix run , se crea en la carpeta routes un archivo con la siguiente
sintaxis de anidamiento:
guitarras.$guitarraUrl.jsx Este caso especifico guitarras es el Api ID en plural que me da
strapi y guitarra es el Api en singular, url se refiere al atributo url de cada guitarra
para que lea el atributo dinamicamente o la url con el nombre de la guitarra, se debe crear
un archivo con una sintaxis de nombre especial:
Debe iniciar con signo de $ ,despues se coloca el nombre que se quiere y es .jsx, tenendo en
cuenta que la forma en que se nombre ese archivo va a ser la forma en que se recupera el
parametro desde la url al hacer el loader y la consulta api.
en params nos trae guitarraUrl que es como se nombro ese parametro, con esta informacion
podemos hacer la consulta para traernos esa guitarra en especifico de la API, es vital saber
que al hacer el loader de todas las guitarras este params trae toda la data de la API y se
renderiza un componete guitarra por cada elemento del arreglo, esto se hace con el .map
function Tienda() {
const guitarras = useLoaderData()
return (
<main className="contenedor">
<h2 className="heading">Nuestra Colección</h2>
{guitarras?.length &&(
<div className="guitarras-grid">
{ guitarras.map(guitarra=>(
<Guitarra
guitarra={guitarra?.attributes}
key={guitarra?.id} />
))}
</div>
)}
</main>
)
}
Cuando se creo el contenido de la API se creo un atributo url, que es unico y es amigable
para SEO, para formar la url de la consulta fetch se coloca de la siguiente forma:
localhost:1337/api/guitarras?filters[url]=valorurl&populate=imagen
El signo de interrogacion eso es a lo que se le llama "URL Query string". El ?"" se utiliza
para dividir el URL del Query string. El Query string es básicamente una lista de variables
y sus valores
el & es para decirle que busque ese otro atributo, es un ‘Y’ esto tambien
esta url se usa en la consulta fetch getGuitarra que estara en el archivo de modelos
guitarras.server.js
return [ ]
}
Este data es de los params de remix, esto es un arreglo que en la posicion 0 tiene un objeto
que es el data de los datos de strapi
{
id: 5,
attributes: {
nombre: 'Townshend',
createdAt: '2023-05-29T21:18:56.226Z',
updatedAt: '2023-05-29T21:19:03.885Z',
descripcion: 'Sed convallis dui elementum, ultricies urna vitae, consequat lacus. Duis a
tristique mi, ac auctor lorem. Curabitur eu erat tempor, aliquet metus pharetra, efficitur
augue. Fusce consectetur sapien ut varius lacinia. Etiam mollis commodo purus id fringilla',
precio: 489,
url: 'townshend',
publishedAt: '2023-05-29T21:18:56.226Z',
imagen: { data: [Object] }
}
}
y nos da este objeto, para acceder a los datos de la guitarra
{
id: 5,
attributes: {
nombre: 'Townshend',
createdAt: '2023-05-29T21:18:56.226Z',
updatedAt: '2023-05-29T21:19:03.885Z',
descripcion: 'Sed convallis dui elementum, ultricies urna vitae, consequat lacus. Duis a
tristique mi, ac auctor lorem. Curabitur eu erat tempor, aliquet metus pharetra, efficitur
augue. Fusce consectetur sapien ut varius lacinia. Etiam mollis commodo purus id fringilla',
precio: 489,
url: 'townshend',
publishedAt: '2023-05-29T21:18:56.226Z',
imagen: { data: [Object] }
}
}
console.log(data.data[0].attributes.nombre)
Cuando se hace la consulta en la aPI trae el objeto Data, si no existe algo ese objeto data
viene vacion y eso produce un error en remix ya que remix intenta leer los attributes..
el manejo de errores en remix se hace a traves del uso del hook useCatch y de los
componentes CatchBaoundary y ErrorBoundary
if (isRouteErrorResponse(error)) {
return (
<Document>
<p className="error">
{error.status} {error.statusText}
</p>
</Document>
);
}
}
Esto lo que hace es que cuando existe un error en la ruta componente , el componente
ErrorBoundary sera renderizado en su lugar, anidado dentro de cualesquiera rutas padres.
Los componentes ErrorBoundary ademas se renderizan cuando hay un error en las
funciones loader o action de una ruta, de forma tal que todos los errores para esa ruta
puedan ser manejados en un solo sitio.
Al igual que con las guitarras, debemos crear una funcion en el modelo para hacer el fetch
de la API, en este caso se crea unarchivo llamado posts.server.jsx, alli se crea una funcion
exportada para hacer la consulta fetch.
En la ruta Blog se crea la funcion loader que llama a la funcion getPosts del modelo para
renderizar lo que viene de la API de strapi, de aquí viene post.attributes que es quein
contiene la informacion del post
return posts.data
}
El componente haciendo el llmado a renderizar el componente post por cada elemento post
del arreglo posts que viene de la API (se usa .map())
function Blog() {
const posts =useLoaderData()
//console.log(posts)
return (
<main clasName="contenedor">
<h2 className="heading">Blog</h2>
<div className="blog">
{posts.map(post=>(
<Post
key={post.id}
post={post}
/>
))}
</div>
</main>
)
}
<div>
<img src={imagen.data.attributes.formats.small.url} alt={titulo}/>
<div className="contenido">
<h3>{titulo}</h3>
<p classNAme="fecha">{publishedAt}</p>
<p className="resumen">{contenido}</p>
<Link className="enlace" to ={`/posts/${url}`}>Leer Post</Link>
</div>
</div>
</article>
)
}
.post .resumen{
display:-webkit-box;
-webkit-box-orient:vertical;
-webkit-line-clamp: 4;
overflow: hidden;
}
Se crea una carpeta llmada utils, dentro de ella se crea un archivo helpers.js, la extension en
.js porque no se mezclara codigo js con html.
Formatear fecha:
Se crea una funcion que recibe la fecha que viene como dato del blog de la consulta a la
API , se convierte a un objeto fecha para usar el metodo .toLocaleDateString().
return fechaNueva.toLocaleDateString('es-ES',opciones)
}
export default {
formatearFecha
}
const {guitarras,posts}=useLoaderData()
Luego de tener el objeto resultado de la consulta fetch en la API se extraen esos datos para
pasarlos a los componentes correspondientes y se rendericen.
Ejemplo
en la funcion componente Index
{guitarras?.length &&(
<div className=”contenedor-guitarras”>
{guitarras.map((meal => (
<Guitarra
key={guitarra?.id}
guitarra={guitarra?.attributes}
/>
)))
</div>)}
{posts?.length &&(
<div className=”contenedor-posts”>
{posts.map((post)=>(
<Post
key={post?.id}
post={post?.attributes}
/>
))}
</div>
)}
<style jsx="true">{`
.curso {
background-image: linear-gradient( to right, rgb(0 0 0 / .65),
rgb(0 0 0 / .7) ), url(${imagen.data.attributes.url})
}
`}</style>
Nested Routes:
La idea general de la asignación de rutas a segmentos de la URL permite que la URL
completa se asigne a una jerarquía de componentes de ruta y dependencias de datos que se
pueden conocer antes de la representación.
Remix usa el archivo root.jsx ubicado en el directorio app como el archivo de entrada base
para renderizar cada ruta; se puede pensar en el archivo root.jsx como el contendor global
de tu aplicación, el cual usa Remix para cargar o renderizar las rutas correspomndientes.
Sin embargo un componente outlet es requerido dentro del archivo root.jsx par que Remix
sea capaz de averiguar que ruta cargar
Ahora que hemos colocado el componente outlet dentro de este componente, este sera
responsable de descubrir que ruta cargar en este componente, dependiendo de la url
visitada. Si visitamos una url que encaje con una ruta, este componente outlet lo descifrara
y cargara alli la ruta correspondiente.
Retornaemos un simple “Hello World” desde routes/index.jsx y tratamos de visitar esa ruta,
la cual es el homepage (/) de nuestra aplicación
El resultado sEria:
Hello World
como es esperado, nuestro archivo global root.jsx fue renderiado al DOM y, a traves del
uso del componente outlet, la correspondiente ruta visitada fue montada (anidada) dentro de
el.
Lo mismo pasaria con cualquier ruta visitada: El archivo root.jsx actua como base
contenedora de las rutas mientras que el componente outlet descifra que ruta debe ser
cargada dependiendo de la url visitada
Imagina por un momento que estamos construyendo un dashboard de ventas de algun tipo,
y en nuestro directorio de rutas creamos un archivo dashboard.jsx.
routes
┣ dashboard.jsx
┗ index.jsx
Por defecto, si visitamos la ruta /dashboard , Remix renderizaria este archivo. Ahora,
imagina que hemos creado un nuevo directorio con el mismo nombre que nuestro archivo
dasboard y, en este nuevo archivo de directorio, creamos otro archivo llamado sales.jsx
routes
┣ dashboard
┃ ┗ sales.jsx
┣ dashboard.jsx
┗ index.jsx
Remix automaticamente asociaria esta nueva carpeta de ruta /dashboard al archivo de ruta
dashboard.jsx e intenta anidar cada ruta ubicada dentro de esta carpeta /dashboard dentro
del layout dashboard.jsx
https://remix.run/docs/en/1.15.0/file-conventions/route-files-v2#nested-routes
<form className="formulario">
<label htmlFor="cantidad">Cantidad</label>
<select id="cantidad"
onChange={e=>setCantidad(+ e.target.value)}
>
<option value="">--Selecccione--</option>
<option value="1" >1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
</select>
<input
type="submit"
value="Agregar al carrito"
/>
</form>
Crear el state para guardar en este caso la cantidad ya que al colocar el formulario en el
componente de la guitarra seleccionada tenemos acceso a sus datos que vienen del loader.
function Guitarra() {
const [cantidad,setCantidad] =useState(0);
Se asigna el valor de cantidad cuando cambie el option del select, con el evento onChange
<select id="cantidad"
onChange={e=>setCantidad(+ e.target.value)}
>
CONTEXT API
Mantener Estado Global sin dependencias, permite evitar tener que pasar el estado desde el
componente a otro a traves de props.
Puedes pasar el state o funciones desde un componente principal hasta los hijos, sin
necesidad de pasarlo por cada componente. Tiene su propio Hook llamado useContext.
Remix y Next JS tienen un context integrado, por eso cuando con ellos no e usa
useContext.
Tambien se puede pasar o actualizar el state desde el componente hijo (o ejecutar una
funcion que lo actualice)
Se puede tener un archivo con el estado global y todas las funciones que modifican el state
y pasarlo o actualizar el estado ya sea con un click o cuando se descargue una lista de
clientes, etc.
Si deseas crear librerias para react, Context es la forma de hacerlo. Basicamente context va
a ser un componente y una vez que se importe se tiene acceso a las funciones en cualquier
lugar de la aplicación. Es muy parecido a los hooks useLoaderData, esta inspirado en esto.