lunes, 6 de mayo de 2024

Taller TypeScript con REACT ( I )



Instalaciones necesarias

 

·        Vscode

·        Postman

·        Mongo Compass

·        Mongo Compass es el software por excelencia para la visualización de bases de datos MongoDB, oficial y desarrollado por Mongo. Te permitirá conectarte a cualquier base de datos, local o remota, para visualizar las colecciones y los documentos en tu base.

·        Node js

·        Android Studio

 

Refuerzo de React

Temas puntuales de la sección

En esta sección veremos los siguientes temas:

·        ¿Por qué es bueno usar TypeScript en mis proyectos?

·        Tipos básicos

·        Objetos e interfaces

·        Hooks de React

o   useState

o   useEffect

o   useRef

o   useReducer

·        Custom Hooks

·        Genericos de TypeScript

·        Axios

·        Tipado de peticiones HTTP

·        Formularios

 

Por qué TypeScript

Porque si y punto. 😝

Inicio de proyecto (Introducción React con TypeScript)

Voy a crear una carpeta donde vamos a estar creando todos nuestros ejercicios, la voy a llamar React-Native y la coy abrir en VScode:



Vamos ahora a abrir una terminal y pasarle la dirección de nuestra carpeta (arrastrando la carpeta a la consola,para crear una aplicación de react):


En este caso me faltaba el paquete vite, me pide que lo instala le digo que si.

Le doy un nombre a mi proyecto React; react-foundation. Y me pide que seleccione un  framework


Con las flechas selecciono react y después selecciono la primera opción para Type>Scrript


Enseguida nos crea nuestro proyecto en la carpeta seleccionada:

Ahora antes de lanzar los comandos que se nos indica , vamos a renombrar la carpeta 01-react-foundation:


Ahora si ejecutamos los comandos indicados en orden


Y una vez que termine podemos lanzar el comando code . que nos abrirá el proyecto en VScode:




Este es un proyecto de REACT no de REACT-NATIVE

Ahora en la consola que tenemos abierta (y si no nos situamos en la carpeta del proyecto) lanzamos el comando npm run dev:


Esto nos devuelve la url del proyecto:

Si la seguimos tendremos en el navegador nuestro proyecto REACT.



Preparar el Proyecto

Vamos a “limpiar” nuestro proyecto React de cosas que no vamos a necesitar (algo muy parecidoa lo que hacíamos en Vue) Para empezar vamos a srcàassetsàreact.sgv


Este componente no lo vamos a necesitar así que lo eliminamos

Ahora iremos a nuestro main.tsx


import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
 
ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
)

 

Podemos ver que estamos trabajando en modo estricto de React y es lo que queremos.

Vayamos ahora a App.tsx



Y borraremos todo lo que está dentro del return, nos quedamos con:

import { useState } from ‘react’
import reactLogo from ‘./assets/react.svg’
import viteLogo from ‘/vite.svg’
import ‘./App.css’
 
function App() {
  const [count, setCount] = useState(0)
 
  return (
    <>
 
    </>
  )
}
 
export default App

 

al hacer esto nos marca errores en los import. Solo con borrar el useStatese arregla, también borraremos todas las importaciones que nos están generando error y vamos a añadir un sencillo h1 entre las etiquetas main:

import './App.css'
 
function App() {
 
  return (
    <main>
      <h1>Introducciín a TypeScript - React</h1>
    </main>
  )
}
 
export default App
 

 

si ahora lanzamos nuestra app desde la consola:





Estructura del proyecto

Vamos ahora a crear la estructura de directorios, para ello nos situamos sobre la carpeta src y en ella vamos a ir creando los siguientes directorios:

Api



Components

Luego crearemos otro directorio que se va a llamar Components:


import './App.css'
 
function App() {
 
  return (
    <main>
     <h1>Introducción a TypeScript - React</h1>
 
     {/* Aquí mis componentes */}
     
    </main>
  )
}
 
export default App


  

Hooks

Crearemos ahora otra carpeta que llamaremos hooks




Interfaces

Crearemos una nueva carpeta que se llamará interfaces:



Store

Crearemos ahora una carpeta que llamaremos store:



TypeScript

Y por último crearemos una carpeta que se llamará typescript:





Entonces esta es la estructura completa de directorios que vamos a utilizar para esa app

Ahora necesitamos ir a nuestro main.tsx, donde podemos ver que tenemos una referencia a nuestro index.css:


En App.tsx tenemos una referencia a App.css, que no vamos a necesitar:

import './App.css'
 
function App() {
 
  return (
    <main>
     <h1>Introducción a TypeScript - React</h1>
 
     {/* Aquí mis componentes */}
 
    </main>
  )
}
 
export default App
 

 

y también podemos borrar el archivo App.css ya que no lo vamos a usar:



Si vemos nuestra App, veremos que como nos hemos cargado el App.css no tenemos aplicados algunos estilos



Vamos a arreglar esto, nos vamos a ir a nuestro archivo index.css y al final del todo vamos a añadir un etiqueta main, donde vamos a adarle algunos estilos básicos:

main {
  align-items: center;
  display: flex;
  flex-direction: flex;
  justify-content: center;
  width: 100vw;
}
 

 

Si salvamos veremos que en nuestra app se aplican ya estos estilos de nuevo:


Vamos a añadir algunos estilos más:

input {
  padding: 5px;
  margin-bottom: 10px;
}

 Tipos básicos TypeScript

Ha llegado el momento de comenzar con TypeScript. En la carpeta de Typescript vamos a crear nuestro primer Functional component que llamaremos BasicTypes.tsx

La extensión tsx, es para typescript x, si estuviéramos trabajando con JavaScript sería jsx.



Creando nuestro primer componente funcional (Functional Component)

En nuestro archivo recién creado BasycTypes vamos a escribir un primer componente funcional:

export const BasycTypes = () => {
    return (
        <div>BasicTypes</div>
    )
}

 

Como puedes ver un componente funcional, nos es más que una función anónima auto ejecutables guardada en una constante con un nombre, en este caso la hemos llamado BasicTypes.

Salvamos y antes de hacer nada más, podemos ir a la carpeta typescript y añadir un nuevo archivo que vamos a llamar index.ts (observa que es extensión ts y no tsx)



Esto que acabamos de hacer se conoce como un archivo de barril. Lo que vamos a hacer en el index.ts es simplemente exportar todo de nuestro archivo tsx BasycTypes:

Index.tsx

export * from './BasicTypes';

de este modo, cuanod yo haga importaciones de esta carpeta TypeScript, puedo apuntar directamente a este archivo index.ts.

Vayamos ahora a nuestro archivo App.tsx

 
function App() {
 
  return (
    <main>
     <h1>Introducción a TypeScript - React</h1>
 
     {/* Aquí mis componentes */}
 
    </main>
  )
}
 
export default App

y justo donde hemos comentado lo de Aquí mis componentes, vamos a invocar nuestro archivo  BasicTypes (que es el contiene nuestro primer functional component)

import { BasicTypes } from "./typescript"
 
function App() {
 
  return (
    <main>
     <h1>Introducción a TypeScript - React</h1>
 
     {/* Aquí mis componentes */}
     <BasicTypes />
 
    </main>
  )
}
 
export default App

 

Nota cómo aquí la importación se está haciendo desde  ./typescript  (en morado) y no desde ./typescript/index.ts

Esto último es lo que REACT está buscando, pero como en la carpeta typescript tenemos un index no hace falta escribirlo ya que automáticamente lo va a buscar dentro de ese directorio typescript.

 Si vamos a ver nuestra app, veremos que ahora al lado del h1 aparece el texto basictypes:



Se ve bastante mal y esto es debido a que en el CSS (index.css) el flex direction lo dejamos en flex pero para que se apliten los componentes, necesitamos que sea column:

main {
  align-items: center;
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100vw;
}
 
input {
  margin-bottom: 10px;
  padding: 5px;
}

 

Si salvamos y vamos a nuestra app veremos que ahora los componentes se apilan en columnas:




Trabajando en nuestro Functional Component

Vamos a nuestro archivo BasicTypes, donde tenemos nuestro primer componente funcional BasicTypes, y vamos a empezar a trabajar en él.

Vamos a crear un fragmento con un h3 que diga tipos básicos:

export const BasicTypes = () => {
    return (
       <>
       <h3>Tipos básicos</h3>
       </>
    )
}



Y ahora en el cuerpo de nuestro functional component, vamos a estudiar un par de tipos básicos de TypeScript:

Por ejemplo yo puedo tener una constante de tipo string que guarde mi nombre:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
 
    return (
       <>
       <h3>Tipos básicos</h3>
       </>
    )
}

 

Ahora para usar esa constante name, lo invoco en el return y ya está:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}




Nada sorprendente, nada del otro mundo, pero démonos cuenta de algo, si dejamos el cursor encima, de la invocación del componente se nos informa que es de tipo string:



TypeScript es lo suficientemente inteligente para inferir el tipo de dato, es decir que si yo ahora en la declaración de mi constante le quito el tipo:

export const BasicTypes = () => {
 
    const name = 'Juanjo';
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

Si vuelvo aponer el cursor encima de la invocación de mi constante, esta VEZ SE ME INFORMA QUE ES DE TIPO Juanjo


Esto puede parecer algo extraño. Lo que pasa es que como es una constante jamás va a cambiar de valor, por eso TypeScript nos está diciendo que el valor de la constante name es de tipo Juanjo, esto es algo interesante aunque sabemos que es un string, pero es interesante que tengamos esta opción.

Como sabemos que name es de tipo string, si yo le añado el punto veo que tengo todos los métodos y propiedades que yo espero de un string:


Por ejemplo, métodos de empieza con, termina con, el path, replace, Split, es decir todos lo métodos propios de un string.

Del mismo modo si yo ahora a la variable name le doy como valor un número, TypeScript lo infiere y del mismo modo me daría todos los métodos del tipo number:




Todo esto lo hago para que nos quede claro que TypeScript es capaz de inferir el tipo de una variable o constante. esto es importante porque yo no necesito memorizar cada uno d ellos métodos que tiene cada tipo.

Por último, otra cosa que debemos entender es que si yo ahora hago la constante name igual a un Array:

export const BasicTypes = () => {
 
    const name = ['Juanjo', 'Fernando'];
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

 Si yo ahora pongo el cursor encima TypeScript me va  informar de que ahora la constante name es del tipo Arreglo de Strings:


Lógicamente name no es un buen nombre para un array, solo pretendo que tengamos claro que se nos va a dar ayuda respecto del tipado de las variables y constantes y objetos, así como de los métodos asociados a cada tipo.

Es por esto que resulta muy beneficiososo trabajar con un tipado estricto, como nos ofece TypeScript. Visto todo esto volvamos a dejar nuestra variable name como al principio con su tipado en la msma declaración:

export const BasicTypes = () => {
 
    const name:string = 'Juanjo';
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

 

Añadiendo más constantes

Sigamos viendo más cosas, ahora por ejemplo podríamos añadir mas constantes de distintos tipos:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
    const age: number = 48;
    const isActive: boolean = true;
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

 

Supongamos que después tenemos una constante que queremos que sea de tipo Array y lo queremos inicializar vacío:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
    const age: number = 48;
    const isActive: boolean = true;
 
    const powers = [];
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

 

Lo podemos inicializar vacío, pero esto va generar un tipado muy interante, si pongo el cursor encima veremos que nos está diciendo que es del tipo any:


En algunos lugares puede darse el caso que nos diga que es de tipo unknown, en algunas compilaciones de Typescript, a veces sale como unkown, y yo puedo incluso declararlo así, dándole ese tipo:

const powers:unknown = [];

 

Cuando nos arroja un unkown, esto quiere decir es que no sabe el tipo de dato, pero esto es diferente al caso que nos ocupa que es que sea de tipo any

El tipo any significa que en ese arreglo, constante, variable, podemos colocar cualquier tipo de dato, Números, booleanos, strings, numbers, objetos etc. Esto es como báscicamente trabaja JavaScript.

Sin embargo, TypeScript va intentar siempre ponerle algún tipo de dato estricto. Nosotros queremos evitar el tipo any por que al admitir cualquier tipo de dato, esto hace que nuestro código sea más difícil de mantener.

La forma de actuar en TypeScript, sería declararlo diciéndole que es un arreglo de strings y que lo inicializo vacío:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
    const age: number = 48;
    const isActive: boolean = true;
 
    const powers: string[] = [];
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

 

O bien podría darle valores en la declaración:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
    const age: number = 48;
    const isActive: boolean = true;
 
    const powers: string[] = ['React', 'ReactNative', 'Angular', 'Vue'];
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name }
       </>
    )
}

 Por fin en el return de mi componente funcional puedo ir mostrando mis constantes que serán renderizadas en la app:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
    const age: number = 48;
    const isActive: boolean = true;
 
    const powers: string[] = ['React', 'ReactNative', 'Angular', 'Vue'];
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name } { age } { isActive? 'true': 'false'}
       <br />
       {powers}
       </>
    )
}

 

En mi app podré ir viendo lo que me devuelve mi componente funcional

Esta es la forma en que react imprime un objeto, podría usar el join para separarlos por una coma por ejemplo:

export const BasicTypes = () => {
 
    const name: string = 'Juanjo';
    const age: number = 48;
    const isActive: boolean = true;
 
    const powers: string[] = ['React', 'ReactNative', 'Angular', 'Vue'];
 
    return (
       <>
       <h3>Tipos básicos</h3>
       { name } { age } { isActive? 'true': 'false'}
       <br />
       {powers.join(', ')}
       </>
    )
}



Esta sería básicamente una introducción a los tipos básicos en TypeScript, hemos visto que el tipado fuerte tiene muchas ventajas frente al tipado débil de JS, por ejemplo, si yo quisiera ahora hacer un push de números a mi array de strings: