diff --git a/04-frameworks/01-react/01-previous/01-concepts/readme.md b/04-frameworks/01-react/01-previous/01-concepts/readme.md new file mode 100644 index 000000000..4fb3a2dae --- /dev/null +++ b/04-frameworks/01-react/01-previous/01-concepts/readme.md @@ -0,0 +1,312 @@ +# 01 Previous - Hi React + +## Summary + +In this example we are going to create a _codesandbox_ to understand the first concepts of React and the main reasons why we need a library like this. +[Here you have the complete example that we are going to develop.](https://codesandbox.io/p/sandbox/react-concepts-rncyq4) + +To begin, we will start from a vanilla JavaScript project and gradually add features that bring us closer to the approach proposed by React. The goal is to see how React solves common web development problems in a more elegant and powerful way. + +## Step by step + +- Rename the file _index.mjs_ to _index.js_ and update the reference in _index.html_. +- Comment out all the content of _index.js_. +- In _index.html_ render a static list of users: + +_index.html_ + +```diff + + + + JavaScript Sandbox + + + + +-
++
++

Lista de usuarios

++
1955: Rick Sánchez
++
8765: Beth Harmon
++
7562: Farrokh Bulsara
++
+ + + +``` + +This works, but frameworks like React offer us a different approach: they allow us to dynamically transform the DOM in the client. This way, the server only delivers a basic HTML along with a JavaScript file that generates the interface. + +We leave the HTML empty and move the list into our _index.js_: + +_index.html_ + +```diff + + + + JavaScript Sandbox + + + + ++
+-
+-

Lista de usuarios

+-
1955: Rick Sánchez
+-
8765: Beth Harmon
+-
7562: Farrokh Bulsara
+-
+ + + +``` + +_index.js_: + +```diff ++ import "./styles.css"; + ++ document.getElementById("app").innerHTML = ` ++

Lista de usuarios

++
1955: Rick Sánchez
++
8765: Beth Harmon
++
7562: Farrokh Bulsara
++ `; +``` + +Now the content is generated by JavaScript. We can confirm that it’s the JavaScript file that generates the content. + +### Components + +Let’s start breaking our list into parts. First, we separate the title: + +```diff + import "./styles.css"; + ++ const Header = () => { ++ return `

Lista de usuarios

`; ++ }; ++ + document.getElementById("app").innerHTML = ` +-

Lista de usuarios

++ ${Header()} +
1955: Rick Sánchez
+
8765: Beth Harmon
+
7562: Farrokh Bulsara
+``` + +This function we just created, in React, is a component. That is, **in React, components are functions.** For now, this component returns a piece of our application, in this case the title, which renders something in the DOM. + +Let’s continue splitting or componentizing our application. We’ll create a new component that returns just the list.. + +```diff +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + ++ const List = () => { ++ return ` ++
++
1955: Rick Sánchez
++
8765: Beth Harmon
++
7562: Farrokh Bulsara
++
`; ++ }; + +document.getElementById("app").innerHTML = ` + ${Header()} +-
1955: Rick Sánchez
+-
8765: Beth Harmon
+-
7562: Farrokh Bulsara
++ ${List()} +`; +``` + +### Props + +Now let’s create a component that renders each user in the DOM. To do this, we’ll create a component (function) that receives a user object with an `id` and `name`: + +```diff +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + ++ const User = (props) => { ++ return `
${props.id}: ${props.name}
`; ++ }; + +const List = () => { + return ` +
++ ${User({id: 1955, name 'Rick Sánchez'})} ++ ${User({id: 8765, name 'Beth Harmon'})} ++ ${User({id: 7562, name 'Farrokh Bulsara'})} +-
1955: Rick Sánchez
+-
8765: Beth Harmon
+-
7562: Farrokh Bulsara
+
`; +}; + +document.getElementById("app").innerHTML = ` + ${Header()} + ${List()} +`; +``` + +In React jargon, the input arguments we pass to components are known as `props`. A bit later we’ll see that in React, the syntax for running a component is very different from this. However, it’s very important to keep in mind that even though the syntax is different, in the end what we’re doing is invoking functions and passing them input arguments. + +Let’s get a little closer to what a real application would do and simulate that the data we display in the list comes from an API. For this, let’s create a file _./api.js_. + +```js +export const getUsers = () => [ + { id: 1955, name: "Rick Sánchez" }, + { id: 8765, name: "Beth Harmon" }, + { id: 7562, name: "Farrokh Bulsara" }, +]; +``` + +When invoking it inside the `List` function, we can directly use a `map` method to execute the `User` function for each element of the array, no matter how many there are. + +```diff ++ import { getUsers } from './api'; +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + ++ const User = (props) => { ++ return `
${props.id}: ${props.name}
`; ++ }; + +const List = () => { ++ const users = getUsers(); + return ` +
++ ${users.map(user=>User(user)).join('')} +- ${User({id: 1955, name 'Rick Sánchez'})} +- ${User({id: 8765, name 'Beth Harmon'})} +- ${User({id: 7562, name 'Farrokh Bulsara'})} +
`; +}; + +document.getElementById("app").innerHTML = ` + ${Header()} + ${List()} +`; +``` + +In React, however, the `props` argument is a single parameter: an object to which I can pass whatever I want. Let’s adapt the code. + +```diff +import { getUsers } from "./api"; +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + +- const User = (props) => { ++ const User = ({ user }) => { +- return `
${props.id}: ${props.name}
`; ++ return `
${user.id}: ${user.name}
`; +}; + +const List = () => { + const users = getUsers(); + return ` +
+- ${users.map((user) => User(user)).join("")} ++ ${users.map((user) => User({ user })).join("")} +
`; +}; + +document.getElementById("app").innerHTML = ` + ${Header()} + ${List()} +`; +``` + +### Reactivity + +Let’s try to render a random number for each element, calculated at the moment the component is invoked. + +```diff +const User = ({ user }) => { ++ const randomNumber = Math.random(); +- return `
${user.id}: ${user.name}
`; ++ return `
${user.id}: ${user.name} - ${randomNumber}
`; +}; +``` + +If we update it with a setTimeout, we see the value changes in the console, but the interface does not update: + +```diff +const User = ({ user }) => { +- const randomNumber = Math.random(); ++ let randomNumber = Math.random(); ++ setTimeout(() => { ++ randomNumber = Math.random(); ++ console.log(randomNumber); ++ }, 3000); + return `
${user.id}: ${user.name} - ${randomNumber}
`; +}; +``` + +Why doesn’t the interface refresh after the three seconds of the setTimeout? Try to think of the answer... + +The explanation is simple: functions are executed only once. At that moment they return something that generates a fragment of HTML. That initial result is what gets injected into the DOM and doesn’t change again, even though the internal logic of the function (like the value of `randomNumber`) does get updated later. + +If we look at the console, we see that the value of `randomNumber` is indeed recalculated, but the interface doesn’t reflect that change. This happens because the DOM is not automatically linked to the data of our application. + +And this is where libraries like React come in. Their main value is that they incorporate reactivity: they allow us to keep the application state and the user interface in sync. + +In React, states are the key piece to persist and manage data. Every time a state changes, React re-executes the components that depend on it, ensuring the interface updates and stays aligned with the most recent information. + +### Events and persistence + +```diff +const List = () => { +- const users = getUsers(); ++ let users = getUsers(); + ++ const handleClick = () => { ++ alert("button clicked!"); ++ users = [...users, { id: 1234, name: "John Doe" }]; ++ }; + + return ` +
+ ${users.map((user) => User({ user })).join("")} ++ +
`; +}; +``` + +The button appears but when clicking it, not even the alert shows up. What’s going on? +Again, when `List` is executed, the `handleClick` function is created. However, that function doesn’t run until we click the button, and when that happens, the function no longer exists, because the `List` function has already executed and died. + +This is another problem React solves, since it allows us to persist data and functions between executions of our components. + +To leave the example ready for the next exercise, let’s make the following change: + +```diff ++ export default function App() { ++ return ` ++ ${Header()} ++ ${List()} ++ `; +} + ++ document.getElementById("app").innerHTML = App(); +- document.getElementById("app").innerHTML = ` +- ${Header()} +- ${List()} +- `; +``` diff --git a/04-frameworks/01-react/01-previous/01-concepts/readme_es.md b/04-frameworks/01-react/01-previous/01-concepts/readme_es.md new file mode 100644 index 000000000..01b70766e --- /dev/null +++ b/04-frameworks/01-react/01-previous/01-concepts/readme_es.md @@ -0,0 +1,312 @@ +# 01 Previo - Hola React + +## Resumen + +En este ejemplo vamos a crear un _codesandbox_ para entender los primeros conceptos de React y los motivos principales por los que necesitamos una librería como esta. +[Aquí tenéis el ejemplo completo que vamos a desarrollar.](https://codesandbox.io/p/sandbox/react-concepts-rncyq4) + +Para comenzar, partiremos de un proyecto en vanilla JavaScript e iremos añadiendo poco a poco funcionalidades que nos acerquen al enfoque que propone React. El objetivo es ver cómo React resuelve de forma más elegante y potente problemas comunes del desarrollo web. + +## Paso a paso + +- Renombramos el archivo _index.mjs_ a _index.js_ y actualizamos la referencia en _index.html_. +- Comentamos todo el contenido de _index.js_. +- En el fichero _index.html_ vamos a renderizar de forma estática una lista de usuarios: + +_index.html_ + +```diff + + + + JavaScript Sandbox + + + + +-
++
++

Lista de usuarios

++
1955: Rick Sánchez
++
8765: Beth Harmon
++
7562: Farrokh Bulsara
++
+ + + +``` + +Esto funciona, pero frameworks como React nos ofrecen un enfoque distinto: permiten transformar dinámicamente el DOM en el cliente. Así, el servidor solo entrega un HTML básico junto con un archivo JavaScript que genera la interfaz. + +Dejamos el HTML vacío y movemos la lista a nuestro archivo _index.js_: + +_index.html_ + +```diff + + + + JavaScript Sandbox + + + + ++
+-
+-

Lista de usuarios

+-
1955: Rick Sánchez
+-
8765: Beth Harmon
+-
7562: Farrokh Bulsara
+-
+ + + +``` + +Y en _index.js_: + +```diff ++ import "./styles.css"; + ++ document.getElementById("app").innerHTML = ` ++

Lista de usuarios

++
1955: Rick Sánchez
++
8765: Beth Harmon
++
7562: Farrokh Bulsara
++ `; +``` + +Ahora el contenido lo genera JavaScript. Comprobamos que es el fichero de JavaScript el que me genera el contenido. + +### Componentes + +Vamos a ir partiendo nuestra lista en partes. Para ello primero segregamos el título: + +```diff + import "./styles.css"; + ++ const Header = () => { ++ return `

Lista de usuarios

`; ++ }; ++ + document.getElementById("app").innerHTML = ` +-

Lista de usuarios

++ ${Header()} +
1955: Rick Sánchez
+
8765: Beth Harmon
+
7562: Farrokh Bulsara
+``` + +A esta función que acabamos de crear, en React, la vamos a llamar componente. Es decir, **en React los componentes son funciones.** Por el momento este componente nos devuelve un trocito de nuestra aplicación, en este caso el título, que renderiza algo en el DOM. + +Vamos a seguir rompiendo o componentizando nuestra aplicación. Vamos a crear un componente nuevo que nos devuelva la lista únicamente. + +```diff +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + ++ const List = () => { ++ return ` ++
++
1955: Rick Sánchez
++
8765: Beth Harmon
++
7562: Farrokh Bulsara
++
`; ++ }; + +document.getElementById("app").innerHTML = ` + ${Header()} +-
1955: Rick Sánchez
+-
8765: Beth Harmon
+-
7562: Farrokh Bulsara
++ ${List()} +`; +``` + +### Props + +Vamos a crear ahora un componente que me renderice en el DOM, cada usuario. Para ello vamos a crear un componente (función) que reciba un objeto usuario con un `id` y un `name`: + +```diff +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + ++ const User = (props) => { ++ return `
${props.id}: ${props.name}
`; ++ }; + +const List = () => { + return ` +
++ ${User({id: 1955, name 'Rick Sánchez'})} ++ ${User({id: 8765, name 'Beth Harmon'})} ++ ${User({id: 7562, name 'Farrokh Bulsara'})} +-
1955: Rick Sánchez
+-
8765: Beth Harmon
+-
7562: Farrokh Bulsara
+
`; +}; + +document.getElementById("app").innerHTML = ` + ${Header()} + ${List()} +`; +``` + +En el argot de react los argumentos de entrada que les pasamos a los componentes se les conoce por el nombre de `props`. Un poco más adelante veremos que además, en React, la sintaxis para ejecutar un componente es muy distinta a ésta. Sin embargo, es muy importante tener presente que a pesar de que esta sintaxis sea distinta, al final lo que estamos haciendo es invocar funciones y pasándoles argumentos de entrada. + +Vamos a acercarnos un poquito más a lo que haría una aplicación real y a simular que los datos que estamos mostrando por la lista nos llegan de una API. Para ello vamos a crearnos un fichero _./api.js_. + +```js +export const getUsers = () => [ + { id: 1955, name: "Rick Sánchez" }, + { id: 8765, name: "Beth Harmon" }, + { id: 7562, name: "Farrokh Bulsara" }, +]; +``` + +Al invocarlo dentro de la función `List` podemos usar directamente un método `map` para poder ejecutar la función `User` por cada uno de los elementos del array, sean los que sean. + +```diff ++ import { getUsers } from './api'; +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + ++ const User = (props) => { ++ return `
${props.id}: ${props.name}
`; ++ }; + +const List = () => { ++ const users = getUsers(); + return ` +
++ ${users.map(user=>User(user)).join('')} +- ${User({id: 1955, name 'Rick Sánchez'})} +- ${User({id: 8765, name 'Beth Harmon'})} +- ${User({id: 7562, name 'Farrokh Bulsara'})} +
`; +}; + +document.getElementById("app").innerHTML = ` + ${Header()} + ${List()} +`; +``` + +En react sin embargo el argumento `props` es un único parámetro, un objeto al que voy a poder pasar todo lo que quiera. Adaptamos el código. + +```diff +import { getUsers } from "./api"; +import "./styles.css"; + +const Header = () => { + return `

Lista de usuarios

`; +}; + +- const User = (props) => { ++ const User = ({ user }) => { +- return `
${props.id}: ${props.name}
`; ++ return `
${user.id}: ${user.name}
`; +}; + +const List = () => { + const users = getUsers(); + return ` +
+- ${users.map((user) => User(user)).join("")} ++ ${users.map((user) => User({ user })).join("")} +
`; +}; + +document.getElementById("app").innerHTML = ` + ${Header()} + ${List()} +`; +``` + +### Reactividad + +Vamos a intentar renderizar por cada elemento un número random, que se calcule en el momento en el que se invoque nuestro componente. + +```diff +const User = ({ user }) => { ++ const randomNumber = Math.random(); +- return `
${user.id}: ${user.name}
`; ++ return `
${user.id}: ${user.name} - ${randomNumber}
`; +}; +``` + +Si lo actualizamos con un setTimeout, vemos que el valor cambia en consola, pero la interfaz no se actualiza: + +```diff +const User = ({ user }) => { +- const randomNumber = Math.random(); ++ let randomNumber = Math.random(); ++ setTimeout(() => { ++ randomNumber = Math.random(); ++ console.log(randomNumber); ++ }, 3000); + return `
${user.id}: ${user.name} - ${randomNumber}
`; +}; +``` + +¿Por qué transcurridos los tres segundos del setTimeout la interfaz de nuestra aplicación no se refresca? Intentad pensar la respuesta... + +La explicación es sencilla: las funciones se ejecutan únicamente una vez. En ese momento devuelven un return que genera un fragmento de HTML. Ese resultado inicial es el que se inyecta en el DOM y no vuelve a cambiar, aunque la lógica interna de la función (como el valor de `randomNumber`) sí se modifique posteriormente. + +Si observamos la consola, veremos que el valor de `randomNumber` efectivamente se recalcula, pero la interfaz no refleja ese cambio. Esto ocurre porque el DOM no está vinculado de manera automática a los datos de nuestra aplicación. + +Y aquí es donde entran en juego librerías como React. Su principal valor es que incorporan reactividad: permiten mantener sincronizados el estado de la aplicación y la interfaz de usuario. + +En React, los estados son la pieza clave para persistir y gestionar datos. Cada vez que un estado cambia, React vuelve a ejecutar los componentes que dependen de él, asegurando que la interfaz se actualice y quede alineada con la información más reciente. + +### Eventos y persistencia + +```diff +const List = () => { +- const users = getUsers(); ++ let users = getUsers(); + ++ const handleClick = () => { ++ alert("button clicked!"); ++ users = [...users, { id: 1234, name: "John Doe" }]; ++ }; + + return ` +
+ ${users.map((user) => User({ user })).join("")} ++ +
`; +}; +``` + +El botón aparece pero al clicar en él, no aparece ni siquiera el alert. ¿Qué está pasando? +De nuevo, cuando `List` se ejecuta, la función `handleClick` se crea. Sin embargo, esa función no se ejecuta hasta que clicamos en el botón y cuando esto ocurre, la función ya no existe, porque la función `List` se ha ejecutado y ha muerto. + +Este es otro de los problemas que va a venir a solucionar React, ya que nos va a permitir, persistir datos, funciones entre ejecución y ejecución de nuestros componentes. + +De cara a dejar el ejemplo preparado para el siguiente ejercicio vamos a hacer el siguiente cambio: + +```diff ++ export default function App() { ++ return ` ++ ${Header()} ++ ${List()} ++ `; +} + ++ document.getElementById("app").innerHTML = App(); +- document.getElementById("app").innerHTML = ` +- ${Header()} +- ${List()} +- `; +``` diff --git a/04-frameworks/01-react/01-previous/02-basic/readme.md b/04-frameworks/01-react/01-previous/02-basic/readme.md new file mode 100644 index 000000000..939a1d2ee --- /dev/null +++ b/04-frameworks/01-react/01-previous/02-basic/readme.md @@ -0,0 +1,217 @@ +# 01 Basic - Hi React + +We are going to migrate the JavaScript application from _01-concepts_ ato react. [Here you have the complete example we are going to develop](https://codesandbox.io/p/sandbox/react-basic-h9rhkk) For this, we’ll create a React codesandbox.. + +We create the same file _./api.js_ + +```js +export const getUsers = () => [ + { id: 1955, name: "Rick Sánchez" }, + { id: 8765, name: "Beth Harmon" }, + { id: 7562, name: "Farrokh Bulsara" }, +]; +``` + +Next, from the example we left ready in _01-concepts_, we are going to copy and paste _index.js_. We are only going to change what each of the components returns. The reason is that in React, components return `jsx` elements, which is nothing more than syntactic sugar for JavaScript. + +**We replace string literals with jsx elements in the components:** + +For example in the `Header` component: + +- In Javascript: + +```js +const Header = () => { + return `

Lista de usuarios

`; +}; +``` + +- In React: + +```jsx +const Header = () => { + return

Lista de usuarios

` +}; +``` + +If we apply the same type of change in the rest of the components, the index.jsx file should look like this: + +```jsx +import React from "react"; +import { getUsers } from "./api"; +import "./styles.css"; + +const Header = () => { + return

Lista de usuarios

; +}; + +const User = ({ user }) => { + let randomNumber = Math.random(); + + setTimeout(() => { + randomNumber = Math.random(); + console.log(randomNumber); + }, 3000); + + return ( +
+ {user.id}: {user.name} - {randomNumber} +
+ ); +}; + +const List = () => { + const users = getUsers(); + return
{users.map((user) => User({ user }))}
; +}; + +export default function App() { + return ( +
+ {Header()} + {List()} +
+ ); +} +``` + +We check that our application renders the list on the screen. + +**React syntax** +In React we are able to use `jsx` syntax when we invoke our components: + +```diff +export default function App() { + return ( +
++
++ +- {Header()} +- {List()} +
+ ); +} +``` + +Also, if we want to pass an argument through props (the input arguments to our component): + +```diff +const List = () => { + const users = getUsers(); +- return
{users.map((user) => User({ user }))}
; ++ return
{users.map((user) => )}
; +}; +``` + +When doing this, the console will throw an error that appears when we render elements by iterating over a list. As we can see in the trace, it asks us to pass the component a unique `key` value (later on we’ll see why this is necessary): + +```diff +const List = () => { + const users = getUsers(); +- return
{users.map((user) => )}
; ++ return
{users.map((user) => )}
; +}; +``` + +But as we can see, the `randomNumber` variable is still out of sync with our user interface. This happens because we are not storing that value in state, so React doesn’t know about the change. To make our application reactive, we make the following change: + +```diff +const User = ({ user }) => { +- let randomNumber = Math.random(); ++ const [randomNumber, setRandomNumber] = React.useState(Math.random()) + + +setTimeout(() => { +- randomNumber = Math.random(); ++ setRandomNumber(Math.random()); + console.log(randomNumber); +}, 3000); + + + return ( +
+ {user.id}: {user.name} - {randomNumber} +
+ ); +}; +``` + +If we look closely, we see that even though it’s a setTimeout (which should execute only once), it’s actually running every three seconds. Why? + +In the code, the setTimeout is inside the body of the component. That means every time the component re-renders, React creates a new setTimeout. + +When the setTimeout finishes, it calls setRandomNumber, which changes the state. That state change triggers a new render, and in that render a new setTimeout is created again. This creates an infinite loop: + +1. Execution/render → creates setTimeout. +2. SetTimeout → randomNumber changes state. +3. React detects state change → React re-renders component. +4. Back to step 1. + +The key: it’s not that the setTimeout repeats automatically, but that it gets recreated on every execution. + +When we write logic directly inside a React component, that logic will run on every render. This can cause performance issues, application errors, or even infinite loops (like in this setTimeout case, which gets recreated every render). + +To control when and under what conditions some code executes, React gives us the useEffect hook, which allows us to manage side effects (like timers, API requests, or event subscriptions) in a controlled way. + +Its syntax is: + +```jsx +useEffect(() => { + // 👇 Código (efecto) que quieres ejecutar +}, [dependencias]); +``` + +Parameters of useEffect: + +- Callback (effect): the function we want to execute. +- Dependency list: an array that tells React when to re-run the callback. + +Examples: + +- [] → the effect runs only once, when the component mounts. +- [state] → the effect runs every time that state changes. +- undefined → the effect runs on every render. + +So, we use `useEffect` with an empty dependency array, because we want the setTimeout to run only once, when the component is created: + +```diff +const User = ({ user }) => { +const [randomNumber, setRandomNumber] = React.useState(Math.random()) + ++ React.useEffect(()=>{ +setTimeout(() => { + setRandomNumber(Math.random()); + console.log(randomNumber); +}, 3000); ++ },[]) + + return ( +
+ {user.id}: {user.name} - {randomNumber} +
+ ); +}; +``` + +Now let’s create a button that, when clicked, adds a new element to the list: + +```diff +const List = () => { +- const users = getUsers(); ++ Const [users, setUsers] = React.useState(getUsers()); + ++ const handleClick = () => { ++ setUsers([...users, {id: 1234, name: 'John Doe'}]) ++ } + +- return return
{users.map((user) => )}
; ++ return ( ++
++ {users.map((user) => ( ++ ++ ))} ++ ++
++ ); +}; +``` diff --git a/04-frameworks/01-react/01-previous/02-basic/readme_es.md b/04-frameworks/01-react/01-previous/02-basic/readme_es.md new file mode 100644 index 000000000..e8660f13b --- /dev/null +++ b/04-frameworks/01-react/01-previous/02-basic/readme_es.md @@ -0,0 +1,217 @@ +# 01 Basic - Hola React + +Vamos a migrar la aplicación en Javascript de _01-concepts_ a react. [Aquí tenéis el ejemplo completo que vamos a desarrollar](https://codesandbox.io/p/sandbox/react-basic-h9rhkk) Para ello vamos a crearnos un codesandbox de react. + +Creamos el mismo fichero _./api.js_ + +```js +export const getUsers = () => [ + { id: 1955, name: "Rick Sánchez" }, + { id: 8765, name: "Beth Harmon" }, + { id: 7562, name: "Farrokh Bulsara" }, +]; +``` + +A continuación, desde el ejemplo que hemos dejado preparado en _01-concepts_ vamos a copiar y pegar _index.js_. Vamos a cambiar únicamente lo que devuelve cada uno de los componentes. El motivo es que en react, los componentes devuelven elementos `jsx`, que no es más que azúcar sintáctico de javascript. + +**Reemplazamos literales por elementos jsx en los componentes:** + +Por ejemplo, en el componente `Header`: + +- En código Javascript: + +```js +const Header = () => { + return `

Lista de usuarios

`; +}; +``` + +- En código React: + +```jsx +const Header = () => { + return

Lista de usuarios

` +}; +``` + +Si aplicamos el mismo tipo de cambio en el resto de componentes, el fichero _index.jsx_ nos tendría que quedar así: + +```jsx +import React from "react"; +import { getUsers } from "./api"; +import "./styles.css"; + +const Header = () => { + return

Lista de usuarios

; +}; + +const User = ({ user }) => { + let randomNumber = Math.random(); + + setTimeout(() => { + randomNumber = Math.random(); + console.log(randomNumber); + }, 3000); + + return ( +
+ {user.id}: {user.name} - {randomNumber} +
+ ); +}; + +const List = () => { + const users = getUsers(); + return
{users.map((user) => User({ user }))}
; +}; + +export default function App() { + return ( +
+ {Header()} + {List()} +
+ ); +} +``` + +Comprobamos que nuestra aplicación renderiza la lista por la pantalla. + +**Sintaxis React** +En React vamos a poder usar la sintaxis _jsx cuando_ invocamos nuestros componentes: + +```diff +export default function App() { + return ( +
++
++ +- {Header()} +- {List()} +
+ ); +} +``` + +Además, si queremos pasar un argumento por props (argumentos de entrada a nuestro componente): + +```diff +const List = () => { + const users = getUsers(); +- return
{users.map((user) => User({ user }))}
; ++ return
{users.map((user) => )}
; +}; +``` + +Al hacer esto, la consola nos va a lanzar un error que aparece cuando renderizamos elementos iterando por una lista. Como vemos en la traza, nos pide que le pasemos al componente una key con valor único (ya veremos más adelante a que se debe): + +```diff +const List = () => { + const users = getUsers(); +- return
{users.map((user) => )}
; ++ return
{users.map((user) => )}
; +}; +``` + +Pero, como estamos viendo la variable `randomNumber` sigue estando desincronizada de nuestra interfaz de usuario. Esto se debe a que no estamos guardando ese valor en un estado, por lo que react no se entera del cambio. Para que nuestra aplicación sea reactiva hacemos el siguiente cambio: + +```diff +const User = ({ user }) => { +- let randomNumber = Math.random(); ++ const [randomNumber, setRandomNumber] = React.useState(Math.random()) + + +setTimeout(() => { +- randomNumber = Math.random(); ++ setRandomNumber(Math.random()); + console.log(randomNumber); +}, 3000); + + + return ( +
+ {user.id}: {user.name} - {randomNumber} +
+ ); +}; +``` + +Si nos fijamos vemos, que a pesar de que es un setTimeout (debería ejecutarse una sola vez), se está ejecutando cada tres segundos ¿Por qué? + +En el código, el setTimeout está dentro del cuerpo del componente. Eso significa que cada vez que el componente se re-ejecuta, React vuelve a crear un nuevo setTimeout. + +Cuando el setTimeout se cumple, llama a setRandomNumber, lo cual cambia el estado. Ese cambio de estado provoca un nuevo renderizado, y en ese nuevo renderizado se vuelve a crear otro setTimeout. Así entras en un bucle infinito: + +1. Ejecución/render → crea setTimeout. +2. SetTimeout → randomNumber cambia estado. +3. React detecta cambio de estado → React ejecuta componente de nuevo. +4. Vuelve al paso 1. + +La clave: no es que el setTimeout se repita automáticamente, sino que se vuelve a crear en cada ejecución. + +Cuando escribimos lógica directamente dentro de un componente de React, esa lógica se va a ejecutar en cada renderizado. Esto puede generar problemas de rendimiento, fallos en la aplicación, o incluso bucles infinitos (como en el caso de setTimeout, que se vuelve a crear en cada render). + +Para controlar cuándo y con qué condiciones se ejecuta cierto código, React nos proporciona el hook `useEffect`, que nos permite manejar efectos secundarios (side effects), como temporizadores, peticiones a APIs o suscripciones a eventos, de forma controlada. + +Su sintaxis es la siguiente: + +```jsx +useEffect(() => { + // 👇 Código (efecto) que quieres ejecutar +}, [dependencias]); +``` + +Parámetros de useEffect: + +- Callback (efecto): la función que queremos ejecutar. +- Lista de dependencias: un array que indica cuándo debe volver a ejecutarse ese callback. + +Ejemplos: + +- [] → el efecto solo se ejecuta una vez, cuando el componente se monta. +- [estado] → el efecto se ejecuta cada vez que cambia estado. +- undefined → el efecto se ejecuta en cada renderizado. (evitar) + +Así, usamos `useEffect` con un array de dependencias vacío, porque queremos que el `setTimeout` se ejecute una sola vez, cuando se crea el componente: + +```diff +const User = ({ user }) => { +const [randomNumber, setRandomNumber] = React.useState(Math.random()) + ++ React.useEffect(()=>{ +setTimeout(() => { + setRandomNumber(Math.random()); + console.log(randomNumber); +}, 3000); ++ },[]) + + return ( +
+ {user.id}: {user.name} - {randomNumber} +
+ ); +}; +``` + +Vamos a crear ahora un button que al clicar, me añada un nuevo elemento a la lista: + +```diff +const List = () => { +- const users = getUsers(); ++ Const [users, setUsers] = React.useState(getUsers()); + ++ const handleClick = () => { ++ setUsers([...users, {id: 1234, name: 'John Doe'}]) ++ } + +- return return
{users.map((user) => )}
; ++ return ( ++
++ {users.map((user) => ( ++ ++ ))} ++ ++
++ ); +}; +``` diff --git a/04-frameworks/01-react/01-previous/readme.md b/04-frameworks/01-react/01-previous/readme.md deleted file mode 100644 index e69de29bb..000000000 diff --git a/04-frameworks/01-react/01-previous/readme_es.md b/04-frameworks/01-react/01-previous/readme_es.md deleted file mode 100644 index f5b2f8b53..000000000 --- a/04-frameworks/01-react/01-previous/readme_es.md +++ /dev/null @@ -1,185 +0,0 @@ -# 01 Previo - Hola React - -## Resumen - -En este ejemplo vamos a usar _codesandbox_ para crear nuestro primer proyecto en React. - -Puedes encontrar el ejemplo ya implementado en esta URL: https://codesandbox.io/s/strange-tdd-evsp07 - -## Paso a paso - -- Codesandbox es una herramienta que nos permite crear proyectos de prueba en React, Angular, Vue, - o TS / ES6 plano trabajando directamente en nuestro navegador web. - -- Si entramos podemos elegir un nuevo proyecto, vamos a seleccionar React + JS. - -- Este proyecto se crea usando una plantilla de _create-react-app_, más adelante sabremos más - sobre este cli, ahora nos vamos a centrar en que estructura tiene una aplicacíon react. - -- Primero vamos a abrir el fichero _index.html_ que se encuentra bajo la carpeta public, - lo más importante que podemos destacar aquí es el siguiente div: - -_./public/index.html_ - -```html -
-``` - -- Ese es el punto de entrada para nuestra aplicación React. - -- React es una librería que no está hecha sólo para correr en un navegador web, la podemos - encontrar también disponible para, por ejemplo, desarrollar aplicaciones móviles con - _react native_. Nos hace falta una librería intermedia que se encarga de conectar - React con un navegador web, esta librería es react-dom. - -- Es hora de abrir el fichero que está en _./src/index.js_ aquí vemos como referenciamos - al div root que hemos creado antes, creamos la raíz de la aplicación y la renderizamos, para ello: - - - Obtenemos el elemento del dom con el id "root" (el que estaba creado en el HTML principal). - - Creamos la app React en el elemento root. - - Empezamos a pintarla (fijate que le pasamos el componente raíz App) - -> Ojo esta forma de crear la aplicación React es nueva (desde la versión 18), en versiones anteriores -> se usaba _React.render()_ - -_./public/index.js_ - -```jsx -import { StrictMode } from "react"; -import { createRoot } from "react-dom/client"; - -import App from "./App"; - -const rootElement = document.getElementById("root"); -const root = createRoot(rootElement); - -root.render( - - - -); -``` - -> ¿ Qué es React.StrictMode? Es una ayuda para detectar problemas en tiempo de desarrollo, -> detecta si estamos usando ciclos de vida no seguro de componentes, o apis antiguas, -> más información: https://en.reactjs.org/docs/strict-mode.html - -- Ok, acabamos de instanciar un componente que se llama _App_ ¿Donde podemos encontrar esto? - debajo de _./src/App.js_ en este componente lo que hacemos es mostrar dos textos - -```jsx -export default function App() { - return ( -
-

Hello CodeSandbox

-

Start editing to see some magic happen!

-
- ); -} -``` - -Si te fijas es un componente de tipo función, que devuelve un elemento con dos hijos (los dos H1) - -- Vamos a trabajar un poco más sobre este ejemplo, queremos permitir que el usuario teclee - un nombre y mostrar este nombre por pantalla. - -- Primero nos hace falta guardar el nombre que teclea el usuario en una variable que no - desaparezca una vez que se ha ejecutado la función, para ello usaremos _react.useState_. - -```diff -export default function App() { -+ // React.useState returns an array -+ // item[0] is the getter (returns the username) -+ // item[1] is the setter (let us update the state) -+ // That's why we are appliying here destructuring: -+ const [username, setUsername] = React.useState('No name'); -+ - return ( -
-

Hello CodeSandbox

-

Start editing to see some magic happen!

-
- ); -} -``` - -¿Qué diferencia tiene esto con usar una variable? Si usaramos una variable tal cual -esta se detruiría al terminar la función y se volvería a crear cuando volvieramos a ejecutar -la función, al usar _React.useState_ esta función guarda "en un cajón desastre" el valor que -se estaba editando y lo vuelve a inyectar cuando se vuelve a llamar a la función. - -- Vamos a mostrar el nombre del usuario que está guardado en ese _state_. Esto lo veremos más en - detalle luego, pero abramos boca en este ejemplo, en el código que vemos que parece HTML, - podemos escribir Javascript, ¿Cómo? Encerrandolo entre llaves: - -```diff - return ( -
--

Hello CodeSandbox

-+

{username}

-

Start editing to see some magic happen!

-
- ); -``` - -Aquí estamos diciendo en el _h1_, que ejecuta el código javascript que evalua la variable -_username_ - -- Ahora queremos ir un paso más alla, queremos crear un input que permita al usuario - editar el nombre del usuario, si ponemos algo así como: - -```diff - return ( -
-

{username}

--

Start editing to see some magic happen!

-+ -
- ); -``` - -- Podemos ver como aparece el nombre, pero y si intentamos editar, oye resulta que no se actualiza - esto ¿Por qué? Tenemos que recordar ahora como funcionaba el flujo undireccional, me llegan los - datos, el input dispara un rerender (repintado)y vuelve a leer el del valor de la variable. - -- El input nos expone un evento, _onChange_ que recibe un parametro estandar del _dom_ - accediente a _e.target.value_ tenemos el nuevo valor. - -- Podríamos ahora estar tentados a hacer algo así (OJO esto está mal): - -```diff - return ( -
-

{username}

- username = e.target.value} - > -
- ); -``` - -- ¿Qué pasa con esto? - - - Primero que no debemos de mutar la variable _username_, esa variable - para nosotros es de sólo lectura. - - - Segundo aunque la mutaramos, al volver a repintarse el componente este valor - se pierde. - -- ¿Qué podemos hacer? Utilizar _setUsername_ - -```diff - return ( -
-

{username}

- username = e.target.value} -+ onChange={(e) => setUsername(e.target.value)} - > -
- ); -``` - -- ¡ Ahora si que funciona! _setUsername_ se encarga de enviar la petición a un sitio que - seguirá viviendo aunque la función termina, cuando _setState_ se vuelva a invocar - recupera la información y tendremos nuestro dato disponible. diff --git a/04-frameworks/01-react/02-base/01-create-react-app/readme.md b/04-frameworks/01-react/02-base/01-create-react-app/readme.md deleted file mode 100644 index 28562cc61..000000000 --- a/04-frameworks/01-react/02-base/01-create-react-app/readme.md +++ /dev/null @@ -1,33 +0,0 @@ -# Create React app - -To create such an application - -https://create-react-app.dev/ - -````bash -npx create-react-app my-app -``` - -How to upgrade - -````bash -npm install react-scripts@latest -``` - -Discuss what _npx_ is and why not _npm install create-react-app -g_ - -Comment on structure, and comment on how to create _typescript_ project - -npx create-react-app my-app --template typescript - -And add _TypeScript_ support afterwards - -https://create-react-app.dev/docs/adding-typescript - -Comment eject and you won't see what's going on. - -https://create-react-app.dev/docs/available-scripts/#npm-run-eject - -And more fumada customizing and making your template - -https://auth0.com/blog/how-to-configure-create-react-app/ diff --git a/04-frameworks/01-react/02-base/01-create-react-app/readme_es.md b/04-frameworks/01-react/02-base/01-create-react-app/readme_es.md deleted file mode 100644 index 61abf417b..000000000 --- a/04-frameworks/01-react/02-base/01-create-react-app/readme_es.md +++ /dev/null @@ -1,44 +0,0 @@ -# Create React app - -Para crear una aplicación de este tipo - -https://create-react-app.dev/ - -```bash -npx create-react-app my-app -``` - -Si te da algún problema de versión antigua, prueba a borrar la caché de _npx_ - -```bash -sudo npx clear-npx-cache -``` - -Si un día necesitas hacer un upgrade de un proyecto existente, lo puedes hacer ejecutando el siguiente comando: - -```bash -npm install react-scripts@latest -``` - -Utilizamos _npx_ para traernos siempre la última versión de _create-react-app_. Si lo hicieramos con _npm install create-react-app -g_, -nos instalaría la versión actual en nuestra máquina de forma global, y si creamos una aplicación en un tiempo no utilizaría la última versión. - -Para crear un proyecto con soporte para _typescript_: - -```bash -npx create-react-app my-app --template typescript -``` - -O añadir soporte a _TypeScript_ después: - -https://create-react-app.dev/docs/adding-typescript - -Podemos hacer `eject` de nuestro proyecto y tener acceso directo a la configuración (por ejemplo, de _webpack_): - -https://create-react-app.dev/docs/available-scripts/#npm-run-eject - -Podemos comprobar abriendo la configuración de _webpack_ que es inmanejable. - -Y más fumada customizando y haciendo tu plantilla - -https://auth0.com/blog/how-to-configure-create-react-app/ diff --git a/04-frameworks/01-react/02-base/01-vite-boiler/README.md b/04-frameworks/01-react/02-base/01-vite-boiler/README.md new file mode 100644 index 000000000..ba0ead5f6 --- /dev/null +++ b/04-frameworks/01-react/02-base/01-vite-boiler/README.md @@ -0,0 +1,22 @@ +## 01 Vite boiler plate + +## Summary + +In this example there is a vite boiler plate set up with Typescript support, just in the step before +to adding React support. + +It is based on the Vite examples. + +This example is the only one that doesn't have a step-by-step (if you need guidance, you can go to the +vite examples you'll find in this repository). + +Highlights: + +- Added TypeScript as a local dev dependency. +- Switched project to use ES Modules in package.json. +- Created a `tsconfig.json` with a minimal configuration. +- Vite uses esbuild for transpilation (fast, no type checking). +- Enabled `isolatedModules` and `useDefineForClassFields` for `esbuild`compatibility. + +In the following example we will take this as a starting point and we will go step by step adding +support for React. diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.html b/04-frameworks/01-react/02-base/01-vite-boiler/index.html similarity index 55% rename from 04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.html rename to 04-frameworks/01-react/02-base/01-vite-boiler/index.html index a3d74b719..dd5f1546a 100644 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.html +++ b/04-frameworks/01-react/02-base/01-vite-boiler/index.html @@ -1,12 +1,12 @@ - - - - My App Example + + +
+ diff --git a/04-frameworks/01-react/02-base/01-vite-boiler/package.json b/04-frameworks/01-react/02-base/01-vite-boiler/package.json new file mode 100644 index 000000000..dfcbe9038 --- /dev/null +++ b/04-frameworks/01-react/02-base/01-vite-boiler/package.json @@ -0,0 +1,16 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "typescript": "^5.9.2", + "vite": "^7.1.3", + "vite-plugin-checker": "^0.10.2" + } +} diff --git a/04-frameworks/01-react/02-base/01-vite-boiler/readme_es.md b/04-frameworks/01-react/02-base/01-vite-boiler/readme_es.md new file mode 100644 index 000000000..f74a2d255 --- /dev/null +++ b/04-frameworks/01-react/02-base/01-vite-boiler/readme_es.md @@ -0,0 +1,22 @@ +## 01 Vite boiler plate + +## Resumen + +En este ejemplo desarrollamos un boilerplate de Vite configurado con soporte para TypeScript, justo en el paso previo +a añadir soporte para React. + +Está basado en los ejemplos de Vite. + +Este ejemplo es el único que no tiene una guía paso a paso (si necesitas orientación, puedes consultar los +ejemplos de Vite que encontrarás en este repositorio). + +Puntos destacados: + +- Se agregó TypeScript como dependencia de desarrollo local. +- Se cambió el proyecto para usar ES Modules `package.json`. +- Se creó un `tsconfig.json` con una configuración mínima. +- Vite utiliza esbuild para la transpilación (rápido, sin comprobación de tipos). +- Se habilitó `isolatedModules` y `useDefineForClassFields` para que sea compatible con `esbuild`. + +En el siguiente ejemplo tomaremos este como punto de partida y, paso a paso, añadiremos +soporte para React. diff --git a/04-frameworks/01-react/02-base/01-vite-boiler/src/index.ts b/04-frameworks/01-react/02-base/01-vite-boiler/src/index.ts new file mode 100644 index 000000000..f69b4850f --- /dev/null +++ b/04-frameworks/01-react/02-base/01-vite-boiler/src/index.ts @@ -0,0 +1 @@ +console.log("Vite-boiler-plate"); diff --git a/04-frameworks/01-react/02-base/01-vite-boiler/tsconfig.json b/04-frameworks/01-react/02-base/01-vite-boiler/tsconfig.json new file mode 100644 index 000000000..6414575cc --- /dev/null +++ b/04-frameworks/01-react/02-base/01-vite-boiler/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/02-base/01-vite-boiler/vite.config.ts b/04-frameworks/01-react/02-base/01-vite-boiler/vite.config.ts new file mode 100644 index 000000000..5bfe487c0 --- /dev/null +++ b/04-frameworks/01-react/02-base/01-vite-boiler/vite.config.ts @@ -0,0 +1,6 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; + +export default defineConfig({ + plugins: [checker({ typescript: true })], +}); diff --git a/04-frameworks/01-react/02-base/03-webpack-react/src/index.html b/04-frameworks/01-react/02-base/02-vite-react/index.html similarity index 55% rename from 04-frameworks/01-react/02-base/03-webpack-react/src/index.html rename to 04-frameworks/01-react/02-base/02-vite-react/index.html index a3d74b719..050566921 100644 --- a/04-frameworks/01-react/02-base/03-webpack-react/src/index.html +++ b/04-frameworks/01-react/02-base/02-vite-react/index.html @@ -1,12 +1,13 @@ - - - - My App Example + + + React App +
+ diff --git a/04-frameworks/01-react/02-base/02-vite-react/package.json b/04-frameworks/01-react/02-base/02-vite-react/package.json new file mode 100644 index 000000000..9ee970f00 --- /dev/null +++ b/04-frameworks/01-react/02-base/02-vite-react/package.json @@ -0,0 +1,23 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0" + } +} diff --git a/04-frameworks/01-react/02-base/02-vite-react/readme.md b/04-frameworks/01-react/02-base/02-vite-react/readme.md new file mode 100644 index 000000000..d1e39e3f7 --- /dev/null +++ b/04-frameworks/01-react/02-base/02-vite-react/readme.md @@ -0,0 +1,98 @@ +# 02 Vite boiler plate - React + +## Summary + +This example takes the _01-vite-boiler_ example as a starting point. + +We will go step by step adding the necessary configuration so that we integrate +**React** into our build process. + +# Step by Step + +- First we copy the previous example, and do a _npm install_ + +```bash +npm install +``` + +- Next, install `react` and `react-dom` dependencies: + +```bash +npm install react react-dom --save +``` + +- Install types for `react` y `react-dom` ad dev dependencies: + +```bash +npm install @types/react @types/react-dom -D +``` + +- Now open `tsconfig.json` file and set following compiler option to support `jsx` notation in our TypeScript files: + +_tsconfig.json_ + +```diff + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, ++ "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", +``` + +⚡ `jsx` is a JavaScript syntax extension that will allow us to write HTML-in-JS and is typically used by React components. + +- In order to make `vite` fully support `jsx` syntax (among other things) we will add a plugin, otherwise, `esbuild` won't be able to transpile our `react` source files written in `jsx` syntax: + +```bash +npm install @vitejs/plugin-react --save-dev +``` + +- Finally, let's modify `vite.config.ts` to add the newly installed plugin: + +_vite.config.ts_ + +```diff + import { defineConfig } from "vite"; + import checker from "vite-plugin-checker"; ++ import react from "@vitejs/plugin-react"; + + export default defineConfig({ +- plugins: [checker({ typescript: true })], ++ plugins: [checker({ typescript: true }), react()], + }); + +``` + +- Let's create our first React component. + +_./src/app.tsx_ + +```tsx +import React from "react"; + +export const App = () => { + return

Hello React !!

; +}; +``` + +Lets update our _./src/index.ts_ to _./src/index.tsx_. We also adjust in the _./index.html_ file. + +- It's time to instantiate that main component, to be able to integrate it with the browser we have to make use of _createRoot_. + +```tsx +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./app"; + +const rootElement = document.getElementById("root"); +const root = createRoot(rootElement); + +root.render(); +``` + +- Let's check that things are working as expected: + +```bash +npm start +``` diff --git a/04-frameworks/01-react/02-base/02-vite-react/readme_es.md b/04-frameworks/01-react/02-base/02-vite-react/readme_es.md new file mode 100644 index 000000000..12235b0c7 --- /dev/null +++ b/04-frameworks/01-react/02-base/02-vite-react/readme_es.md @@ -0,0 +1,97 @@ +# 02 Vite boiler plate - React + +## Resumen + +Este ejemplo parte desde el ejemplo _01-vite-boiler_. + +Vamos a ir paso a paso, añadiendo la configuración necesaria para integrar **React**. + +# Paso a paso + +- Antes que nada nos instalamos todos los paquetes necesarios del boiler plate ejecutando _npm install_ + +```bash +npm install +``` + +- A continuación instalamos `react` y `react-dom` como dependencias: + +```bash +npm install react react-dom --save +``` + +- A continuación instalamos los tipos de las librerías `react` y `react-dom` como dependencias de desarrollo: + +```bash +npm install @types/react @types/react-dom -D +``` + +- Para hacer que TS entienda la notación `jsx` añadimos lo siguiente en el fichero `tsconfig.json`: + +_tsconfig.json_ + +```diff + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, ++ "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", +``` + +⚡ `jsx` es azúcar sintáctico que permite escribir HTML-in-JS. Esta sintaxis es la que vamos a usar con los componentes de React. + +- Para hacer que `vite` soporte la sintaxis `jsx` (y otras cosas) tenemos que añadir un plugin, sino, `esbuild` no será capaz de transpilar nuestros ficheros de `react`, escritos en formato en `jsx`: + +```bash +npm install @vitejs/plugin-react --save-dev +``` + +- Finalmente, modificamos `vite.config.ts` añadiendo nuestro plugin: + +_vite.config.ts_ + +```diff + import { defineConfig } from "vite"; + import checker from "vite-plugin-checker"; ++ import react from "@vitejs/plugin-react"; + + export default defineConfig({ +- plugins: [checker({ typescript: true })], ++ plugins: [checker({ typescript: true }), react()], + }); + +``` + +- Creemos ahora nuestro primer componente + +_./src/app.tsx_ + +```tsx +import React from "react"; + +export const App = () => { + return

Hello React !!

; +}; +``` + +Actualizamos _./src/index.ts_ a _./src/index.tsx_. Ajustamos la extensión también en el fichero _./index.html_. + +- Vamos a usar el componente que acabamos de crear. Para poder integrar ese componente (y el resto de la aplicación) en nuestro html, hacemos uso de _createRoot_. + +```tsx +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./app"; + +const rootElement = document.getElementById("root"); +const root = createRoot(rootElement); + +root.render(); +``` + +- Comprobamos que todo funciona + +```bash +npm start +``` diff --git a/04-frameworks/01-react/02-base/03-webpack-react/src/app.tsx b/04-frameworks/01-react/02-base/02-vite-react/src/app.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/03-webpack-react/src/app.tsx rename to 04-frameworks/01-react/02-base/02-vite-react/src/app.tsx diff --git a/04-frameworks/01-react/02-base/02-vite-react/src/index.tsx b/04-frameworks/01-react/02-base/02-vite-react/src/index.tsx new file mode 100644 index 000000000..f323553ef --- /dev/null +++ b/04-frameworks/01-react/02-base/02-vite-react/src/index.tsx @@ -0,0 +1,8 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./app"; + +const rootElement = document.getElementById("root"); +const root = createRoot(rootElement); + +root.render(); diff --git a/04-frameworks/01-react/02-base/02-vite-react/tsconfig.json b/04-frameworks/01-react/02-base/02-vite-react/tsconfig.json new file mode 100644 index 000000000..a057cea1d --- /dev/null +++ b/04-frameworks/01-react/02-base/02-vite-react/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/02-base/02-vite-react/vite.config.ts b/04-frameworks/01-react/02-base/02-vite-react/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/02-base/02-vite-react/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/.babelrc b/04-frameworks/01-react/02-base/02-webpack-boiler/.babelrc deleted file mode 100644 index 3313ff9ef..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/.babelrc +++ /dev/null @@ -1,3 +0,0 @@ -{ - "presets": ["@babel/preset-env", "@babel/preset-typescript"] -} diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/package.json b/04-frameworks/01-react/02-base/02-webpack-boiler/package.json deleted file mode 100644 index 9b1b0de5c..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-typescript": "^7.16.7", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" - } -} diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/readme.md b/04-frameworks/01-react/02-base/02-webpack-boiler/readme.md deleted file mode 100644 index 5fe86d280..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/readme.md +++ /dev/null @@ -1,20 +0,0 @@ -## 02 Web Boiler plate - -## Summary - -In this example there is a webpack boiler plate set up with Typescript support, just in the step before -to adding React support. - -It is based on the Webpack examples. - -This example is the only one that doesn't have a step-by-step (if you need guidance, you can go to the -webpack examples you'll find in this repository). - -Highlights: - -- The webpackconfig has the src folder configured, and the loaders to handle typescript. -- We have babel and typescript configuration files. -- We do the transpilation using babel. - -In the following example we will take this as a starting point and we will go step by step adding -support for React. diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/readme_es.md b/04-frameworks/01-react/02-base/02-webpack-boiler/readme_es.md deleted file mode 100644 index abab80d66..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/readme_es.md +++ /dev/null @@ -1,20 +0,0 @@ -# 02 Web Boiler plate - -## Resumen - -En este ejemplo hay montado un boiler plate en webpack con soporte a Typescript, justo en el paso previo -a añadirle soporte a React. - -Está basado en los ejemplos de Webpack. - -Este ejemplo es el único que no tiene un paso a paso (si necesitas guía puedes ir a los ejemplos -de webpack que encontrarás en este repositorio). - -A destacar: - -- El webpackconfig tiene configurada la carpeta src, y los loaders para manejar typescript. -- Tenemos ficheros de configuracion de babel y typescript. -- Hacemos la transpilación utlizando babel. - -En el siguiente ejemplo tomaremos este como punto de partida y si iremos paso a paso añadiendo -soporte a React. diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/src/index.html b/04-frameworks/01-react/02-base/02-webpack-boiler/src/index.html deleted file mode 100644 index 26e6c384d..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -

Hello World !

- - diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/src/index.tsx b/04-frameworks/01-react/02-base/02-webpack-boiler/src/index.tsx deleted file mode 100644 index 8e1bb81b1..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/src/index.tsx +++ /dev/null @@ -1 +0,0 @@ -console.log("Hello from JS"); diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/tsconfig.json b/04-frameworks/01-react/02-base/02-webpack-boiler/tsconfig.json deleted file mode 100644 index 3312b5f1e..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, - "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/webpack.config.js b/04-frameworks/01-react/02-base/02-webpack-boiler/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/02-base/02-webpack-boiler/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/02-base/04-list-users/src/index.html b/04-frameworks/01-react/02-base/03-list-users/index.html similarity index 55% rename from 04-frameworks/01-react/02-base/04-list-users/src/index.html rename to 04-frameworks/01-react/02-base/03-list-users/index.html index a3d74b719..050566921 100644 --- a/04-frameworks/01-react/02-base/04-list-users/src/index.html +++ b/04-frameworks/01-react/02-base/03-list-users/index.html @@ -1,12 +1,13 @@ - - - - My App Example + + + React App +
+ diff --git a/04-frameworks/01-react/02-base/03-list-users/package.json b/04-frameworks/01-react/02-base/03-list-users/package.json new file mode 100644 index 000000000..9f55e25d6 --- /dev/null +++ b/04-frameworks/01-react/02-base/03-list-users/package.json @@ -0,0 +1,23 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/react": "^19.1.12", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0" + } +} diff --git a/04-frameworks/01-react/02-base/04-list-users/readme.md b/04-frameworks/01-react/02-base/03-list-users/readme.md similarity index 90% rename from 04-frameworks/01-react/02-base/04-list-users/readme.md rename to 04-frameworks/01-react/02-base/03-list-users/readme.md index 33de240fe..d75d8f4e6 100644 --- a/04-frameworks/01-react/02-base/04-list-users/readme.md +++ b/04-frameworks/01-react/02-base/03-list-users/readme.md @@ -1,8 +1,8 @@ -# 04 List Users +# 03 List Users ## Summary -This example takes the _03-webpack-react_ example as a starting point. +This example takes the _02-vite-react_ example as a starting point. We're going to ask the Github API for the list of members that belong to an organisation and display it on the screen. @@ -115,12 +115,9 @@ export const App = () => { With these lines of code, we are iterating through the array of members and creating a span element for each entry, to take into account: -- key: when we create elements dynamically, we need to add a unique key to them (so React can optimise the rendering). - the rendering). - +- key: when we create elements dynamically, we need to add a unique key to them (so React can optimize the rendering). - Member Login: we read the value of the current array element and display the login field. - -- Now that we see that it works we are going to fit this in a grid, let's define some gobal styles +- Now that we see that it works we are going to fit this in a grid, let's define some global styles (check [CSS modules example](https://github.com/Lemoncode/master-frontend-lemoncode/tree/master/03-bundling/01-webpack/12-css-modules), to learn how to configure component isolated CSS) _./src/styles.css_ @@ -150,6 +147,22 @@ body { } ``` +In order to be able to use our styles, we must import them into our project: + +_./index.tsx_ + +```diff +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./app"; ++ import "./styles.css"; + +const container = document.getElementById("root"); +const root = createRoot(container); + +root.render(); +``` + - And let's integrate it in our app component: _./src/app.tsx_ @@ -228,6 +241,8 @@ _./src/app.tsx_ }, []); ``` +A little bit down the module we will see how react 19 brings a specific hook which is ideal for asynchronous operations like data fetching. + What are we doing here? We are making a call to the Github REST API, this api is asynchronous (hence why we use promises), first we parse the result to _json_ and then we assign that result to the state of our component by by invoking _setMembers_ diff --git a/04-frameworks/01-react/02-base/04-list-users/readme_es.md b/04-frameworks/01-react/02-base/03-list-users/readme_es.md similarity index 86% rename from 04-frameworks/01-react/02-base/04-list-users/readme_es.md rename to 04-frameworks/01-react/02-base/03-list-users/readme_es.md index 6667083aa..3ae5f94d9 100644 --- a/04-frameworks/01-react/02-base/04-list-users/readme_es.md +++ b/04-frameworks/01-react/02-base/03-list-users/readme_es.md @@ -1,8 +1,8 @@ -# 04 List Users +# 03 List Users ## Resumen -Este ejemplo toma como punto de partida el ejemplo _03-webpack-react_. +Este ejemplo toma como punto de partida el ejemplo _02-vite-react_. Vamos a pedirle a la API de Github la lista de miembros que pertenece a una organización y vamos a mostrarla por pantalla. @@ -14,7 +14,7 @@ con TypeScript y como hacer nuestro código más mantenible. Que vamos a aprender en este ejemplo: - Cómo crear un componente de visualización sin tener que depender de leer - de una fuenta remota. + de una fuente remota. - Cómo iterar y mostrar una lista de resultados. - Cómo hacer una llámada asícnrona para pedir datos a una api remota. - Cómo meter estos datos en el estado de nuestro componente en React. @@ -36,7 +36,7 @@ npm install https://api.github.com/orgs/lemoncode/members ``` -- Vamos a crear un set de datos parecido que mueste dos miembros de una organización. +- Vamos a crear un set de datos parecido que muestre dos miembros de una organización. _./src/app.tsx_ @@ -125,7 +125,7 @@ a tener en cuenta: - Ahora que vemos que funciona vamos a encajar esto en un tabla: -- Ahora que vemos que funciona vamos a encajar esto en un _grid_, vamos a definir algunos estilos gobales +- Ahora que vemos que funciona vamos a encajar esto en un _grid_, vamos a definir algunos estilos globales (revisa [Ejemplo de módulos CSS](https://github.com/Lemoncode/master-frontend-lemoncode/tree/master/03-bundling/01-webpack/12-css-modules), para aprender a configurar el CSS aislado de los componentes). _./src/styles.css_ @@ -155,6 +155,22 @@ body { } ``` +Para poder usar los estilos tenemos que importarlos dentro de nuestro proyecto: + +_./index.tsx_ + +```diff +import React from "react"; +import { createRoot } from "react-dom/client"; +import { App } from "./app"; ++ import "./styles.css"; + +const container = document.getElementById("root"); +const root = createRoot(container); + +root.render(); +``` + - Y vamos a integrarlo en el componente de nuestra aplicación: _./src/app.tsx_ @@ -183,7 +199,7 @@ export const App = () => { Así que hemos creado aquí un contenedor CSS Grid añadimos la cabecera y un bucle de todos los elementos de la lista de usuarios. - Hasta aquí muy bien pero... yo quiero tirar de la API de Github no de datos mockeados, vamos a empezar - por eliminar los datos mock e inicializar el estado de nuestro componente a un array vacio: + por eliminar los datos mock e inicializar el estado de nuestro componente a un array vacío: ```diff - const membersMock = [ @@ -204,7 +220,7 @@ export const App = () => { + const [members, setMembers] = React.useState([]); ``` -- ¿Cómo puedo hacer la llamada al servidor de Github y traerme los datos justo cuando el compomenten se monte en mi HTML? +- ¿Cómo puedo hacer la llamada al servidor de Github y traerme los datos justo cuando el componente se monte en mi HTML? Para ello vamos a usar _useEffect_ esto lo veremos más adelante cuando cubramos la parte de hooks _./src/app.tsx_ @@ -220,7 +236,7 @@ export const App = () => { ``` Aquí ejecutamos un código justo cuando el componente se monta el DOM, los corchetes que nos encontramos al final de useEffect -son los que indican que sólo se ejecute una sóla vez al montarse el componente, aprenderemos como funciona esto en detalle más adelante. +son los que indican que sólo se ejecute una sola vez al montarse el componente, aprenderemos como funciona esto en detalle más adelante. - Ahora nos queda realizar la llamada AJAX dentro de ese _useEffect_ @@ -234,7 +250,9 @@ _./src/app.tsx_ }, []); ``` -¿Qué estamos haciendo aquí? Estamos haciendo una llamada a la API REST de Github, esta api es asíncrona (de ahí que utlicemos +Más adelante veremos que React 19 ya trae un hook específico para esto. + +¿Qué estamos haciendo aquí? Estamos haciendo una llamada a la API REST de Github, esta api es asíncrona (de ahí que utilicemos promesas), primero parseamos el resultado a _json_ y después asignamos ese resultado al estado de nuestro componente invocando a _setMembers_ diff --git a/04-frameworks/01-react/02-base/04-list-users/src/app.tsx b/04-frameworks/01-react/02-base/03-list-users/src/app.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/04-list-users/src/app.tsx rename to 04-frameworks/01-react/02-base/03-list-users/src/app.tsx diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/index.tsx b/04-frameworks/01-react/02-base/03-list-users/src/index.tsx similarity index 90% rename from 04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/index.tsx rename to 04-frameworks/01-react/02-base/03-list-users/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/index.tsx +++ b/04-frameworks/01-react/02-base/03-list-users/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/02-base/04-list-users/src/styles.css b/04-frameworks/01-react/02-base/03-list-users/src/styles.css similarity index 100% rename from 04-frameworks/01-react/02-base/04-list-users/src/styles.css rename to 04-frameworks/01-react/02-base/03-list-users/src/styles.css diff --git a/04-frameworks/01-react/02-base/03-list-users/tsconfig.json b/04-frameworks/01-react/02-base/03-list-users/tsconfig.json new file mode 100644 index 000000000..a057cea1d --- /dev/null +++ b/04-frameworks/01-react/02-base/03-list-users/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/02-base/03-list-users/vite.config.ts b/04-frameworks/01-react/02-base/03-list-users/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/02-base/03-list-users/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/02-base/03-webpack-react/.babelrc b/04-frameworks/01-react/02-base/03-webpack-react/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/02-base/03-webpack-react/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/02-base/03-webpack-react/package.json b/04-frameworks/01-react/02-base/03-webpack-react/package.json deleted file mode 100644 index 50e9c4ccc..000000000 --- a/04-frameworks/01-react/02-base/03-webpack-react/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" - }, - "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" - } -} diff --git a/04-frameworks/01-react/02-base/03-webpack-react/readme.md b/04-frameworks/01-react/02-base/03-webpack-react/readme.md deleted file mode 100644 index 9efb29473..000000000 --- a/04-frameworks/01-react/02-base/03-webpack-react/readme.md +++ /dev/null @@ -1,114 +0,0 @@ -# 03 Webpack React - -## Summary - -This example takes the _02-webpack-boiler_ example as a starting point. - -We will go step by step adding the necessary configuration so that we integrate -**React** into our build process. - -# Step by Step guide - -- First we copy the previous example, and do a _npm install_ - -```bash -npm install -``` - -- Let's install _react_ and _react-dom_ - -```bash -npm install react react-dom --save -``` - -- Let's install _react_ and _react-dom_ typings - -```bash -npm install @types/react @types/react-dom --save-dev -``` - -This way we have the React library and the bindings to integrate with a web browser. - -- In the index.html we are going to put the _div_ that will serve as entry point to instantiate our React application. our React application. - -_./src/index.html_ - -```diff - --

Hello World !

-+
- -``` - -- Let's create our first React component. - -_./src/app.tsx_ - -```tsx -import React from "react"; - -export const App = () => { - return

Hello React !!

; -}; -``` - -- It's time to instantiate that main component, to be able to integrate it with the browser we have to make use of _createRoot_. - -_./src/index.tsx_ - -```tsx -import React from "react"; -import { createRoot } from "react-dom/client"; -import { App } from "./app"; - -const rootElement = document.getElementById("root"); -const root = createRoot(rootElement); - -root.render(); -``` - -- We are on the right track, but if we try to run this it will fail, since _babel_ does not know how to transform the _jsx_ (remember that this was a sugar, which was actually an XML) into javaScript, in order for babel to be able to understand this we have to install the _preset_ _@babel/preset-react_ - -First we install it and the configure it. - -```bash -npm install @babel/preset-react --save-dev -``` - -_.babelrc_ - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", -+ "@babel/preset-react" - ] -} -``` - -> By the way the _rc_ suffix is pretty usual in linux it's stands for "runcom" -> (CTSS system 1962-63) Script file containing startup instructions for an application program. -> In other words, "rc" is just something that stuck from back in the sixties, and has been used quite often for configuration files in different sorts of programs since, including Node, Babel and many, many others. -> More info [on stackoverflow](https://stackoverflow.com/questions/36212256/what-are-rc-files-in-nodejs). - -> Another curiosity... what is a _preset_ ... let's start with what is a babel plugin: babel transformations are -> enabled by applying plugins, there are plenty of plugins and if you have to go adding one by one it can become a nightmare, -> in order to make this easier, babel has grouped common sets of plugins in _presets_, for instance @babel-preset-react -> includes the following plugins: - -- @babel/plugin-syntax-jsx -- @babel/plugin-transform-react-jsx -- @babel/plugin-transform-react-display-name - -- Is time to double check the _webpack.config.js_ - -- We can make sure that we have _ts_ and _tsx_ as valid extensions. -- Also that in the loader we accept both _ts_ and _tsx_. -- And in the app we have as entry point _index.tsx_. - -* Let's check that things are working as expected: - -```bash -npm start -``` diff --git a/04-frameworks/01-react/02-base/03-webpack-react/readme_es.md b/04-frameworks/01-react/02-base/03-webpack-react/readme_es.md deleted file mode 100644 index bb34f2812..000000000 --- a/04-frameworks/01-react/02-base/03-webpack-react/readme_es.md +++ /dev/null @@ -1,119 +0,0 @@ -# 03 Webpack React - -## Resumen - -Este ejemplo toma como punto de partida el ejemplo _02-webpack-boiler_. - -Vamos a ir paso a paso añdiendo la configuración necesaria para que integrar -**React** en nuestro proceso de build. - -## Paso a Paso - -- Primero copiamos el ejemplo anterior, y hacemos un _npm install_ - -```bash -npm install -``` - -- Vamos a instalar _react_ y _react-dom_ - -```bash -npm install react react-dom --save -``` - -- Vamos a instalarnos los typing de _react_ y _react-dom_ - -```bash -npm install @types/react @types/react-dom --save-dev -``` - -Así tenemos la librería de React y los bindings para que se integre con un navegador web. - -- En el index.html vamos a meter el _div_ que nos servirá como punto de entrada para instanciar - nuestra aplicación React. - -_./src/index.html_ - -```diff - --

Hello World !

-+
- -``` - -- Vamos a crear nuestro primero componente React. - -_./src/app.tsx_ - -```tsx -import React from "react"; - -export const App = () => { - return

Hello React !!

; -}; -``` - -- Es hora de instanciar ese compente principal, para poder integrarlo con el navegador - tenemos que hacer uso a _ReactDOM.render_ - -_./src/index.tsx_ - -```tsx -import React from "react"; -import { createRoot } from "react-dom/client"; -import { App } from "./app"; - -const container = document.getElementById("root"); -const root = createRoot(container); - -root.render(); -``` - -- Vamos por buen camino, pero si intentamos ejecutar esto no va fallar, ya que _babel_ no sabe - como transformar el _jsx_ (recordemos que esto era un azúcar, que en realidad era un XML) a - javaScript, para que babel sea capaz de entender esto tenemos que instalar el _preset_ - _@babel/preset-react_ - -Primero lo instalamos - -```bash -npm install @babel/preset-react --save-dev -``` - -_.babelrc_ - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", -+ "@babel/preset-react" - ] -} -``` - -> Por cierto, el sufijo _rc_ es bastante habitual en linux, significa "runcom". -> (Sistema CTSS 1962-63) Archivo de script que contiene instrucciones de inicio para un programa de aplicación. -> En otras palabras, "rc" es algo que se quedó atrás en los años sesenta, y se ha utilizado con bastante frecuencia para los archivos de configuración en diferentes tipos de programas desde entonces, incluyendo Node, Babel y muchos, muchos otros. -> Más información [en stackoverflow](https://stackoverflow.com/questions/36212256/what-are-rc-files-in-nodejs). - -> Otra curiosidad... qué es un _preset_ ... empecemos por lo que es un plugin de babel: las transformaciones de babel -> se habilitan aplicando plugins, hay un montón de plugins y si tienes que ir añadiendo uno a uno se puede convertir en una pesadilla, -> para hacer esto más fácil, babel ha agrupado conjuntos comunes de plugins en _presets_, por ejemplo @babel-preset-react -> incluye los siguientes plugins: - -- @babel/plugin-syntax-jsx -- @babel/plugin-transform-react-jsx -- @babel/plugin-transform-react-display-name - -- Es hora de saltar al _webpack.config.js_ - -- Nos podemos asegurar de que tenemos como extension valida _ts_ y _tsx_ -- También que en el loader aceptamos tanto _ts_ como _tsx_ -- Y en el app tenemos como punto de entrada _index.tsx_ - -* Vamos a comprobar que hemos dejado todo funcionando: - -```bash -npm start -``` diff --git a/04-frameworks/01-react/02-base/03-webpack-react/tsconfig.json b/04-frameworks/01-react/02-base/03-webpack-react/tsconfig.json deleted file mode 100644 index 3312b5f1e..000000000 --- a/04-frameworks/01-react/02-base/03-webpack-react/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, - "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/04-frameworks/01-react/02-base/03-webpack-react/webpack.config.js b/04-frameworks/01-react/02-base/03-webpack-react/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/02-base/03-webpack-react/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/index.html b/04-frameworks/01-react/02-base/04-list-refactor/index.html similarity index 55% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/index.html rename to 04-frameworks/01-react/02-base/04-list-refactor/index.html index a3d74b719..050566921 100644 --- a/04-frameworks/01-react/02-base/05-list-refactor/src/index.html +++ b/04-frameworks/01-react/02-base/04-list-refactor/index.html @@ -1,12 +1,13 @@ - - - - My App Example + + + React App +
+ diff --git a/04-frameworks/01-react/02-base/04-list-refactor/package.json b/04-frameworks/01-react/02-base/04-list-refactor/package.json new file mode 100644 index 000000000..9ee970f00 --- /dev/null +++ b/04-frameworks/01-react/02-base/04-list-refactor/package.json @@ -0,0 +1,23 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0" + } +} diff --git a/04-frameworks/01-react/02-base/05-list-refactor/readme.md b/04-frameworks/01-react/02-base/04-list-refactor/readme.md similarity index 95% rename from 04-frameworks/01-react/02-base/05-list-refactor/readme.md rename to 04-frameworks/01-react/02-base/04-list-refactor/readme.md index 36c14e9a3..cb2758631 100644 --- a/04-frameworks/01-react/02-base/05-list-refactor/readme.md +++ b/04-frameworks/01-react/02-base/04-list-refactor/readme.md @@ -1,10 +1,10 @@ -# 05 List Refactor +# 04 List Refactor ## Summary -This example takes the _04-list-users_ example as a starting point. +This example takes the _03-list-users_ example as a starting point. -We will add some refactor to enhance project readiblity and maintalibility. +We will add some refactor to enhance project readability and maintainability. ## Step by step guided example @@ -119,7 +119,7 @@ import { MemberEntity } from './model'; ``` > We could even create a subcomponent for the table headers if we wanted to, -> this will be an excercise to do in a next example. +> this will be an exercise to do in a next example. - One last step, the _App_ component still has too much code, it should just instantiate the main component and that's it. the main component and that's it, let's simplify this. @@ -193,5 +193,4 @@ export const App = () => { }; ``` -Can we continue to clean up this code and build something that is maintainable and scalable in the future? The answer is yes, we will see -we'll see later on. +Can we continue to clean up this code and build something that is maintainable and scalable in the future? The answer is yes, we'll see later on. diff --git a/04-frameworks/01-react/02-base/05-list-refactor/readme_es.md b/04-frameworks/01-react/02-base/04-list-refactor/readme_es.md similarity index 93% rename from 04-frameworks/01-react/02-base/05-list-refactor/readme_es.md rename to 04-frameworks/01-react/02-base/04-list-refactor/readme_es.md index 29e7f22fc..09f9382ce 100644 --- a/04-frameworks/01-react/02-base/05-list-refactor/readme_es.md +++ b/04-frameworks/01-react/02-base/04-list-refactor/readme_es.md @@ -1,8 +1,8 @@ -# 05 List Refactor +# 04 List Refactor ## Resumen -Este ejemplo toma como punto de partida el ejemplo _04-list-users_. +Este ejemplo toma como punto de partida el ejemplo _03-list-users_. ## Paso a Paso @@ -14,7 +14,7 @@ npm install - Antes de seguir vamos a arreglar un pequeño bug que dejamos en el ejemplo anterior, se nos olvido poner la key en el map don de generamos dinámicamente - la files con los miembros que pertenecen a una organizacion. + la files con los miembros que pertenecen a una organización. _./src/app.tsx_ @@ -59,8 +59,8 @@ export const App = () => { - Ahora si cometemos una equivocación al escribir uno de los campos en nuestro componente fila, el IDE nos lo marcará en rojo. -- La siguiente mejora que vamos a introducir tiene que ver con el JSX que genramos, - fijate que apenas hemos metido una tabla y ya nos cuesta seguirlo, ¿No podríamos +- La siguiente mejora que vamos a introducir tiene que ver con el JSX que generamos, + fíjate que apenas hemos metido una tabla y ya nos cuesta seguirlo, ¿No podríamos simplificar esto? La respuesta si, podemos extraer la parte que pinta un miembro en la tabla a un componente, esto lo podemos dejar en el mismo fichero o sacarlo a un fichero aparte, vamos a ello: @@ -88,7 +88,7 @@ export const MemberTableRow: React.FC = (props) => { }; ``` -Fijate que interesante como un componente se queda como una caja negra que expone su interacción con +Fíjate que interesante como un componente se queda como una caja negra que expone su interacción con el exterior vía propiedades. - Ahora podemos sustituirlo en App: diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/app.tsx b/04-frameworks/01-react/02-base/04-list-refactor/src/app.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/app.tsx rename to 04-frameworks/01-react/02-base/04-list-refactor/src/app.tsx diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/index.tsx b/04-frameworks/01-react/02-base/04-list-refactor/src/index.tsx similarity index 90% rename from 04-frameworks/01-react/03-react-hooks/04-component_unmount/src/index.tsx rename to 04-frameworks/01-react/02-base/04-list-refactor/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/index.tsx +++ b/04-frameworks/01-react/02-base/04-list-refactor/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/member-table-row.tsx b/04-frameworks/01-react/02-base/04-list-refactor/src/member-table-row.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/member-table-row.tsx rename to 04-frameworks/01-react/02-base/04-list-refactor/src/member-table-row.tsx diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/member-table.tsx b/04-frameworks/01-react/02-base/04-list-refactor/src/member-table.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/member-table.tsx rename to 04-frameworks/01-react/02-base/04-list-refactor/src/member-table.tsx diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/model.ts b/04-frameworks/01-react/02-base/04-list-refactor/src/model.ts similarity index 100% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/model.ts rename to 04-frameworks/01-react/02-base/04-list-refactor/src/model.ts diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/styles.css b/04-frameworks/01-react/02-base/04-list-refactor/src/styles.css similarity index 100% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/styles.css rename to 04-frameworks/01-react/02-base/04-list-refactor/src/styles.css diff --git a/04-frameworks/01-react/02-base/04-list-refactor/tsconfig.json b/04-frameworks/01-react/02-base/04-list-refactor/tsconfig.json new file mode 100644 index 000000000..a057cea1d --- /dev/null +++ b/04-frameworks/01-react/02-base/04-list-refactor/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/02-base/04-list-refactor/vite.config.ts b/04-frameworks/01-react/02-base/04-list-refactor/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/02-base/04-list-refactor/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/02-base/04-list-users/.babelrc b/04-frameworks/01-react/02-base/04-list-users/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/02-base/04-list-users/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/02-base/04-list-users/package.json b/04-frameworks/01-react/02-base/04-list-users/package.json deleted file mode 100644 index 50e9c4ccc..000000000 --- a/04-frameworks/01-react/02-base/04-list-users/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" - }, - "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" - } -} diff --git a/04-frameworks/01-react/02-base/04-list-users/tsconfig.json b/04-frameworks/01-react/02-base/04-list-users/tsconfig.json deleted file mode 100644 index 3312b5f1e..000000000 --- a/04-frameworks/01-react/02-base/04-list-users/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, - "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/04-frameworks/01-react/02-base/04-list-users/webpack.config.js b/04-frameworks/01-react/02-base/04-list-users/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/02-base/04-list-users/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/02-base/06-list-excercise/readme_en.md b/04-frameworks/01-react/02-base/05-list-excercise/readme.md similarity index 87% rename from 04-frameworks/01-react/02-base/06-list-excercise/readme_en.md rename to 04-frameworks/01-react/02-base/05-list-excercise/readme.md index c12899bb4..17e2e52ca 100644 --- a/04-frameworks/01-react/02-base/06-list-excercise/readme_en.md +++ b/04-frameworks/01-react/02-base/05-list-excercise/readme.md @@ -1,6 +1,6 @@ # Summary -Now is your turn to get your hands wet coding some use stories :) +Now is your turn to get your hands wet coding with some challenges :) # Challenges diff --git a/04-frameworks/01-react/02-base/06-list-excercise/readme_es.md b/04-frameworks/01-react/02-base/05-list-excercise/readme_es.md similarity index 86% rename from 04-frameworks/01-react/02-base/06-list-excercise/readme_es.md rename to 04-frameworks/01-react/02-base/05-list-excercise/readme_es.md index 5f38fafcb..ec30268fa 100644 --- a/04-frameworks/01-react/02-base/06-list-excercise/readme_es.md +++ b/04-frameworks/01-react/02-base/05-list-excercise/readme_es.md @@ -1,6 +1,6 @@ # Resumen -Ahora es tu turno de mojarte las manos codificando :) +Ahora es tu turno de mojarte las manos con algunos desafíos :) # Desafíos @@ -23,5 +23,5 @@ Pistas ¿ Qué tienes que tocar? 1. Actualiza el modelo y añade el campo de perfil 2. Actualiza el componente member-table-row, añade una columna más -3. En esa columna muestra el nuevo campo y metelo +3. En esa columna muestra el nuevo campo y mételo dentro de un anchor (un enlace de html) diff --git a/04-frameworks/01-react/02-base/05-list-refactor/.babelrc b/04-frameworks/01-react/02-base/05-list-refactor/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/02-base/05-list-refactor/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/02-base/05-list-refactor/package.json b/04-frameworks/01-react/02-base/05-list-refactor/package.json deleted file mode 100644 index 50e9c4ccc..000000000 --- a/04-frameworks/01-react/02-base/05-list-refactor/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" - }, - "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" - } -} diff --git a/04-frameworks/01-react/02-base/05-list-refactor/tsconfig.json b/04-frameworks/01-react/02-base/05-list-refactor/tsconfig.json deleted file mode 100644 index 3312b5f1e..000000000 --- a/04-frameworks/01-react/02-base/05-list-refactor/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, - "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/04-frameworks/01-react/02-base/05-list-refactor/webpack.config.js b/04-frameworks/01-react/02-base/05-list-refactor/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/02-base/05-list-refactor/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/.babelrc b/04-frameworks/01-react/03-react-hooks/00-boilerplate/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme.md b/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme.md index 1afae0061..441e05ada 100644 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme.md @@ -1,125 +1,16 @@ -# 03 Webpack React +# 02 Vite boiler plate - React ## Summary -This example takes the _02-webpack-boiler_ example as a starting point. - -We will go step by step adding the necessary configuration so that we integrate -**React** into our build process. - -# Step by Step guide - -- First we copy the previous example, and do a _npm install_ - -```bash -npm install -``` - -- Let's install _react_ and _react-dom_ - -```bash -npm install react react-dom --save -``` - -- Let's install _react_ and _react-dom_ typings - -```bash -npm install @types/react @types/react-dom --save-dev -``` - -This way we have the React library and the bindings to integrate with a web browser. - -- In the index.html we are going to put the _div_ that will serve as entry point to instantiate our React application. our React application. - -_./src/index.html_ - -```diff - --

Hello World !

-+
- -``` - -- Let's create our first React component. - -_./src/app.tsx_ - -```tsx -import React from "react"; - -export const App = () => { - return

Hello React !!

; -}; -``` - -- It's time to instantiate that main component, to be able to integrate it with the browser we have to make use of _ReactDOM.render_. - -_./src/index.tsx_ - -```tsx -import React from "react"; -import ReactDOM from "react-dom"; -import { App } from "./app"; - -ReactDOM.render( -
- -
, - document.getElementById("root") -); -``` - -- We are on the right track, but if we try to run this it will fail, since _babel_ does not know how to transform the _jsx_ (remember that this was a sugar, which was actually an XML) into javaScript, in order for babel to be able to understand this we have to install the _preset_ _@babel/preset-react_ - -First we install it and the configure it. - -```bash -npm install @babel/preset-react --save-dev -``` - -_.babelrc_ - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", -+ "@babel/preset-react" - ] -} -``` - -> By the way the _rc_ suffix is pretty usual in linux it's stands for "runcom" -> (CTSS system 1962-63) Script file containing startup instructions for an application program. -> In other words, "rc" is just something that stuck from back in the sixties, and has been used quite often for configuration files in different sorts of programs since, including Node, Babel and many, many others. -> More info [on stackoverflow](https://stackoverflow.com/questions/36212256/what-are-rc-files-in-nodejs). - -> Another curiosity... what is a _preset_ ... let's start with what is a babel plugin: babel transformations are -> enabled by applying plugins, there are plenty of plugins and if you have to go adding one by one it can become a nightmare, -> in order to make this easier, babel has grouped common sets of plugins in _presets_, for instance @babel-preset-react -> includes the following plugins: - -- @babel/plugin-syntax-jsx -- @babel/plugin-transform-react-jsx -- @babel/plugin-transform-react-display-name - -- Is time to double check the _webpack.config.js_ - -- We can make sure that we have _ts_ and _tsx_ as valid extensions. -- Also that in the loader we accept both _ts_ and _tsx_. -- And in the app we have as entry point _index.tsx_. - -* Let's check that things are working as expected: - -```bash -npm start -``` - - - - - - - +Boiler plate extracted from _02-base/02-vite-react_. +Below, main points. For more info, check the original repo or the Vite module. +- Installation of `typeScript` as a local development dependency. +- Installation of `@vitejs/plugin-react` as a local development dependency (support for `jsx` and `tsx`). +- Installation of `react` and `react-dom` as dependencies. +- Installation of the types `@types/react` and `@types/react-dom` as local development dependencies. +- The project was changed to use ES Modules `package.json`. +- A `tsconfig.json` was created with a minimal configuration, prepared to support `jsx` format. +- Vite uses esbuild for transpilation (fast, no type checking). +- `isolatedModules` and `useDefineForClassFields` were enabled to be compatible with `esbuild`. diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme_es.md b/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme_es.md index bb34f2812..f206cfeee 100644 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/Readme_es.md @@ -1,119 +1,16 @@ -# 03 Webpack React +# 02 Vite boiler plate - React ## Resumen -Este ejemplo toma como punto de partida el ejemplo _02-webpack-boiler_. +Boiler plate extraído de _02-base/02-vite-react_. -Vamos a ir paso a paso añdiendo la configuración necesaria para que integrar -**React** en nuestro proceso de build. +A continuación, puntos principales. Para más info, acudir a repo original o módulo de vite. -## Paso a Paso - -- Primero copiamos el ejemplo anterior, y hacemos un _npm install_ - -```bash -npm install -``` - -- Vamos a instalar _react_ y _react-dom_ - -```bash -npm install react react-dom --save -``` - -- Vamos a instalarnos los typing de _react_ y _react-dom_ - -```bash -npm install @types/react @types/react-dom --save-dev -``` - -Así tenemos la librería de React y los bindings para que se integre con un navegador web. - -- En el index.html vamos a meter el _div_ que nos servirá como punto de entrada para instanciar - nuestra aplicación React. - -_./src/index.html_ - -```diff - --

Hello World !

-+
- -``` - -- Vamos a crear nuestro primero componente React. - -_./src/app.tsx_ - -```tsx -import React from "react"; - -export const App = () => { - return

Hello React !!

; -}; -``` - -- Es hora de instanciar ese compente principal, para poder integrarlo con el navegador - tenemos que hacer uso a _ReactDOM.render_ - -_./src/index.tsx_ - -```tsx -import React from "react"; -import { createRoot } from "react-dom/client"; -import { App } from "./app"; - -const container = document.getElementById("root"); -const root = createRoot(container); - -root.render(); -``` - -- Vamos por buen camino, pero si intentamos ejecutar esto no va fallar, ya que _babel_ no sabe - como transformar el _jsx_ (recordemos que esto era un azúcar, que en realidad era un XML) a - javaScript, para que babel sea capaz de entender esto tenemos que instalar el _preset_ - _@babel/preset-react_ - -Primero lo instalamos - -```bash -npm install @babel/preset-react --save-dev -``` - -_.babelrc_ - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", -+ "@babel/preset-react" - ] -} -``` - -> Por cierto, el sufijo _rc_ es bastante habitual en linux, significa "runcom". -> (Sistema CTSS 1962-63) Archivo de script que contiene instrucciones de inicio para un programa de aplicación. -> En otras palabras, "rc" es algo que se quedó atrás en los años sesenta, y se ha utilizado con bastante frecuencia para los archivos de configuración en diferentes tipos de programas desde entonces, incluyendo Node, Babel y muchos, muchos otros. -> Más información [en stackoverflow](https://stackoverflow.com/questions/36212256/what-are-rc-files-in-nodejs). - -> Otra curiosidad... qué es un _preset_ ... empecemos por lo que es un plugin de babel: las transformaciones de babel -> se habilitan aplicando plugins, hay un montón de plugins y si tienes que ir añadiendo uno a uno se puede convertir en una pesadilla, -> para hacer esto más fácil, babel ha agrupado conjuntos comunes de plugins en _presets_, por ejemplo @babel-preset-react -> incluye los siguientes plugins: - -- @babel/plugin-syntax-jsx -- @babel/plugin-transform-react-jsx -- @babel/plugin-transform-react-display-name - -- Es hora de saltar al _webpack.config.js_ - -- Nos podemos asegurar de que tenemos como extension valida _ts_ y _tsx_ -- También que en el loader aceptamos tanto _ts_ como _tsx_ -- Y en el app tenemos como punto de entrada _index.tsx_ - -* Vamos a comprobar que hemos dejado todo funcionando: - -```bash -npm start -``` +- Instalación de `typeScript` como dependencia de desarrollo local. +- Instalación de `@vitejs/plugin-react` como dependencia de desarrollo local (soporte `jsx` y `tsx`) +- Instalación de `react` y `react-dom` como dependencias. +- Instalación de los tipos de `@types/react` y `@types/react-dom` como dependencia de desarrollo local. +- Se cambió el proyecto para usar ES Modules `package.json`. +- Se creó un `tsconfig.json` con una configuración mínima, preparada para soportar formato `jsx`. +- Vite utiliza esbuild para la transpilación (rápido, sin comprobación de tipos). +- Se habilitó `isolatedModules` y `useDefineForClassFields` para que sea compatible con `esbuild`. diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/index.html b/04-frameworks/01-react/03-react-hooks/00-boilerplate/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/package.json b/04-frameworks/01-react/03-react-hooks/00-boilerplate/package.json index 50e9c4ccc..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/package.json +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/package.json @@ -1,39 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.tsx b/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.tsx index 7e439b87e..f323553ef 100644 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.tsx +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/index.tsx @@ -2,7 +2,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; -const container = document.getElementById("root"); -const root = createRoot(container); +const rootElement = document.getElementById("root"); +const root = createRoot(rootElement); root.render(); diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/tsconfig.json b/04-frameworks/01-react/03-react-hooks/00-boilerplate/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/vite.config.ts b/04-frameworks/01-react/03-react-hooks/00-boilerplate/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/00-boilerplate/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/webpack.config.js b/04-frameworks/01-react/03-react-hooks/00-boilerplate/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/00-boilerplate/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/.babelrc b/04-frameworks/01-react/03-react-hooks/01-use-state/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/Readme.md b/04-frameworks/01-react/03-react-hooks/01-use-state/Readme.md index 96b95eb8e..5b7c901c5 100644 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/01-use-state/Readme.md @@ -1,6 +1,6 @@ # 01 Use State -## Resume +## Summary This example takes the _00-boiler-plate_ example as a starting point. @@ -67,8 +67,8 @@ If you come to a React project and you come across code like this, it's a bad sm of the variable _myName_ will always be _John Doe_. Why? the component is just function that is executed over and over on each repaint. -- If we asign a value directly to the _input_ we are skipping two - main pillars of React: unidirection flow and asynchronous state assignment. +- If we assign a value directly to the _input_ we are skipping two + main pillars of React: unidirectional flow and asynchronous state assignment. If you want to see it in action (input not working) you just have to add it to the _app.tsx_ file. @@ -86,7 +86,7 @@ export const App = () => { Ok... How can I handle this? Using React hooks! Let's take a look to _React.useState_, this hook: -- Is initialized with a default value. +- Optionally, it can be initialized to a given value. - It returns an array that contains a getter and a setter (it allows you to access the value that is in useState and allows you diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/Readme_es.md b/04-frameworks/01-react/03-react-hooks/01-use-state/Readme_es.md index b7f71a042..5aa6263e4 100644 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/01-use-state/Readme_es.md @@ -27,7 +27,7 @@ _demo.tsx_ import React from "react"; ``` -Añadimos al fichero un componente de tipo funcion: +Añadimos al fichero un componente de tipo función: _demo.tsx_ @@ -38,15 +38,15 @@ export const MyComponent: React.FC = () => { ``` - Usando la palabra reservada _export_ podemos exponer este fichero al exterior. -- No es extrictamente necesario tiparlo con _React.FC_ (Function Component), pero +- No es estrictamente necesario tiparlo con _React.FC_ (Function Component), pero es buena idea, todo lo que nos atemos a _Typescript_ nos servirá para tener menos dolores de cabeza en el futuro. - El componente no es más que una función que devuelve elementos de React. - Fijate que en este caso no hemos puesto _Props_ ya que no consume ninguna + Fíjate que en este caso no hemos puesto _Props_ ya que no consume ninguna del exterior. - Vamos a por la parte interesante, seguro que nuestra mente Java o Angular - nos mueve a implementar lo siguiente (**IMPORTANTE: ESTO ESTA MAL**). + nos mueve a implementar lo siguiente (**IMPORTANTE: ESTO ESTÁ MAL**). ```diff export const MyComponent : React.FC = () => { @@ -65,7 +65,7 @@ export const MyComponent : React.FC = () => { ``` Si llegáis a un proyecto React y os encontráis código como este, huele a que los -que lo han codificado no se tomaron el tiempo de aprender las bases de esta +que lo han codificado no se tomaron el tiempo de aprender las bases de estas librerías, veamos por qué: - Al crear una variable, cada vez que se vuelva a repintar el componente @@ -93,13 +93,13 @@ export const App = () => { Vale... ¿Cómo puedo manejar esto? ¡Con los hooks de React! Tenemos _React.useState_. -- Se inicializa con un valor por defecto. +- Opcionalmente, se puede inicializar con un valor determinado. - Te devuelve un array que contiene una especie getter y un setter (te permite acceder al valor que está en useState y te permite hacer una petición y setearlo de forma asíncrona). -- La manera más cómoda de consumir lo que devuevel ese _useState_ es hacer +- La manera más cómoda de consumir lo que devuelve ese _useState_ es hacer destructuring sabiendo que el primer elemento del array siempre será nuestro _getter_ y el segundo nuestro \_setter. @@ -156,7 +156,7 @@ setear el estado de _myName_. - Cuando se ejecute el código del componente y llegue a la línea de código que hace el _useState_, en vez de _John Doe_ se le facilitará el nombre que se almaceno con _setState_ -- Al repintar el componente se usará ese nuevo valor mostrandolo +- Al repintar el componente se usará ese nuevo valor mostrándolo por pantalla. Es un cambio de mentalidad grande,... intenta repetir este ejemplo diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/index.html b/04-frameworks/01-react/03-react-hooks/01-use-state/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/01-use-state/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/package.json b/04-frameworks/01-react/03-react-hooks/01-use-state/package.json index 50e9c4ccc..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/package.json +++ b/04-frameworks/01-react/03-react-hooks/01-use-state/package.json @@ -1,39 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/src/index.html b/04-frameworks/01-react/03-react-hooks/01-use-state/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
- - diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/tsconfig.json b/04-frameworks/01-react/03-react-hooks/01-use-state/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/01-use-state/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/vite.config.ts b/04-frameworks/01-react/03-react-hooks/01-use-state/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/01-use-state/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/01-use-state/webpack.config.js b/04-frameworks/01-react/03-react-hooks/01-use-state/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/01-use-state/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/.babelrc b/04-frameworks/01-react/03-react-hooks/02-use-state-object/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme.md b/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme.md index 5b19a0fb3..6fc56879c 100644 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme.md @@ -1,6 +1,6 @@ # 02 Use State Object -## Resume +## Summary This example takes the _01-use-state_ as a starting point. @@ -17,7 +17,7 @@ add an update on a given object, we create a new one). npm install ``` -- Let's go store in the state an object that has the name +- Let's store in the state an object that has the name and last name of a given user. We can write something like: _./src/demo.tsx_ @@ -72,7 +72,7 @@ If we start the application we can see how the name and lastname are displayed.

{userInfo.name} {userInfo.lastname}

-- setMyName(e.target.value)} /> +- setMyName(e.target.value)} /> + userInfo.name = e.target.value} @@ -82,8 +82,8 @@ If we start the application we can see how the name and lastname are displayed. ``` This is not going to work, we are again applying a Java / Angular approach, -we are trying to modify something that is alive only when the function is being -executed, once the component is rerended this value will be lost. +we are trying to modify something that is alive only while the function is being +executed, once the component is rerended this value is be lost. - The way to do this is by creating a new object and assigning it using the _setState_ method. In order to do this copy we use the spread operator (by doing this, all the fields @@ -143,8 +143,7 @@ entry for the one that had changes. ); ``` -Now we can test and see that we can update both the name and -lastname. +Now we can test and see that we can update both the name and lastname. # About Basefactor + Lemoncode diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme_es.md b/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme_es.md index 54880742e..d3d5c39ed 100644 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/Readme_es.md @@ -34,7 +34,7 @@ export const MyComponent: React.FC = () => { Así creamos un estado al que le almacenamos el objeto, pero nos vendría bien tener algo de strong typing que nos ayude a encontrar fallos tontos -del tipo _me olvide poner la "t" en lastname_. +del tipo _me olvidé poner la "t" en lastname_. ```diff + interface UserInfo { @@ -66,7 +66,7 @@ export const MyComponent: React.FC = () => { - Si arrancamos la aplicación podemos ver cómo se muestra el nombre y apellido. - Ahora vamos al turrón, podríamos estar tentados de modificar directamente userInfo y - ver qué pasa, hacer algo así como (**SPOILER ALERT: ESTO ESTA MAL**): + ver qué pasa, hacer algo así como (**SPOILER ALERT: ESTO ESTÁ MAL**): ```diff return ( diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/index.html b/04-frameworks/01-react/03-react-hooks/02-use-state-object/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/package.json b/04-frameworks/01-react/03-react-hooks/02-use-state-object/package.json index 50e9c4ccc..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/package.json +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/package.json @@ -1,39 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/demo.tsx index d4ca6be9a..983a5fdfa 100644 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/demo.tsx +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/demo.tsx @@ -25,6 +25,15 @@ export const MyComponent: React.FC = () => { }) } /> + + setUserInfo({ + ...userInfo, + lastname: e.target.value, + }) + } + /> ); }; diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/index.html b/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
- - diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/tsconfig.json b/04-frameworks/01-react/03-react-hooks/02-use-state-object/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/vite.config.ts b/04-frameworks/01-react/03-react-hooks/02-use-state-object/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/02-use-state-object/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/02-use-state-object/webpack.config.js b/04-frameworks/01-react/03-react-hooks/02-use-state-object/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/02-use-state-object/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/.babelrc b/04-frameworks/01-react/03-react-hooks/03-component-did-onload/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/package.json b/04-frameworks/01-react/03-react-hooks/03-component-did-onload/package.json deleted file mode 100644 index 50e9c4ccc..000000000 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" - }, - "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" - } -} diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/index.html b/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
- - diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/styles.css b/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/styles.css deleted file mode 100644 index 74dc08fbb..000000000 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -.my-text { - color: blue; -} diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/tsconfig.json b/04-frameworks/01-react/03-react-hooks/03-component-did-onload/tsconfig.json deleted file mode 100644 index 3312b5f1e..000000000 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, - "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/webpack.config.js b/04-frameworks/01-react/03-react-hooks/03-component-did-onload/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/Readme.md b/04-frameworks/01-react/03-react-hooks/03-component-mount/Readme.md similarity index 74% rename from 04-frameworks/01-react/03-react-hooks/03-component-did-onload/Readme.md rename to 04-frameworks/01-react/03-react-hooks/03-component-mount/Readme.md index d4824f6b0..3ccf0b864 100644 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/03-component-mount/Readme.md @@ -1,30 +1,30 @@ # 03 Component Did Mount -## Resume +## Summary This example takes as a starting point the _02-use-state-object_ example. Let's start practicing with another React's core hook: _useEffect_ This Hook allows us to subscribe on certain events (check when the -component is mounted, check when the component is unmounted, on +component is mounted, when the component is unmounted, on every render, or when a given property is updated). -Let's start with the most basic, execute a given code when a +Let's start with the most basic: execute a given code when a component is mounted in the DOM. -A common scenario: you want to run some code when a component it's loaded into +A common scenario: running some code when a component it's loaded into the DOM, for example loading a list of clients when the component is mounted. There can be scenarios when we need some code to be executed when a given property value changes or right after each render. -There may be scenarios when all this operations are not synchronous? For instance I want making a call to a server rest api, -this will return a promise, it is not safe at all to run this directly in a functional component -since the functional component is executed and destroyed, to manage these side effects) we can make use of +What if these operations are not synchronous? For instance making a call to a server rest api will return a promise, +so it is not safe at all to run this directly in a functional component, +since the functional component is executed and destroyed (to manage these side effects) we can make use of _React.useEffect_ -In this example we are going to simulate a call to a rest api, in order to retrieve a name (we will use +In this example we are going to simulate a request to a rest api, in order to retrieve a name (we will use _setTimeout_). ## Steps @@ -54,13 +54,13 @@ export const MyComponent = () => { }; ``` -- If we run the example, the name field will be empty, but we want +- If we run the example, the name field will be empty, but how to assign some value right when the component is mounted? We can make use of - _React.useEffect_ passing as a second argument an empty array (that's important + _React.useEffect_, passing as a second argument an empty array (that's important if we don't pass this the code inside the _useEffect_ would be executed on mount and after every render). -_./src/demo.js_ +_./src/demo.tsx_ ```diff import React from "react"; @@ -86,7 +86,7 @@ export const MyComponent = () => { * Let's go one step further, let's simulate an asynchronous call (we will do it using _setTimeout_). -_./src/demo.js_ +_./src/demo.tsx_ ```diff import React from "react"; @@ -111,8 +111,9 @@ export const MyComponent = () => { }; ``` -- Now _John_ is displayed after 1,5 seconds, instead of _setTimeout_ you could - use here _fetch_ or any other similar approach to make an ajax request. +Now _John_ is displayed after 1,5 seconds. +As a next step, instead of a _setTimeout_ you could +use here _fetch_ or any other similar approach to make an ajax request. # About Basefactor + Lemoncode diff --git a/04-frameworks/01-react/03-react-hooks/03-component-mount/index.html b/04-frameworks/01-react/03-react-hooks/03-component-mount/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/03-component-mount/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/03-component-mount/package.json b/04-frameworks/01-react/03-react-hooks/03-component-mount/package.json new file mode 100644 index 000000000..9ee970f00 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/03-component-mount/package.json @@ -0,0 +1,23 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0" + } +} diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/readme_es.md b/04-frameworks/01-react/03-react-hooks/03-component-mount/readme_es.md similarity index 77% rename from 04-frameworks/01-react/03-react-hooks/03-component-did-onload/readme_es.md rename to 04-frameworks/01-react/03-react-hooks/03-component-mount/readme_es.md index ea72abb86..603f93316 100644 --- a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/03-component-mount/readme_es.md @@ -19,9 +19,10 @@ ejemplo cargar una ficha de un cliente de una API REST de servidor. También hay operaciones que queremos poder ejecutar cuando cambie un valor, o en después de cada render. -¿Qué pasa si esas operaciones no son síncronas? Por ejemplo quiero -tirar de un setTimeout o hacer un llamada a un servidor, esto devolvera una promesa, no es nada seguro ejecutar esto directamente en un componente funcional -ya que este se ejecuta y destruye, para esto (gestionar side effects) tenemos +¿Qué pasa si esas operaciones no son síncronas? Por ejemplo si quiero +tirar de un setTimeout o hacer un llamada a un servidor, esto devolverá una promesa. +No es nada seguro ejecutar esto directamente en un componente funcional +ya que este se ejecuta y destruye; para esto (gestionar side effects) tenemos _React.useEffect_ En este ejemplo vamos a ver como cambiar un nombre, justo cuando se @@ -36,7 +37,7 @@ utilizando _setTimeout_. npm install ``` -- Vamos a sobreescribir el fichero _demo.tsx_ con el siguiente código: +- Vamos a sobrescribir el fichero _demo.tsx_ con el siguiente código: ```tsx import React from "react"; @@ -64,7 +65,7 @@ npm start - Vemos que el campo nombre está en blanco, esto es normal ya que le hemos asignado el valor inicialización a cade en blanco. -- ¿Y si quisieramos asignar un valor justo cuando se monta el componente +- ¿Y si quisiéramos asignar un valor justo cuando se monta el componente en el dom? Podemos hacer uso de _React.useEffect_ ```diff @@ -80,7 +81,7 @@ export const MyComponent = () => { Al ejecutar esto podemos ver como aparece el nombre de _John_ por pantalla. -Si depuramos podemos y ponemos un breakpoint justo donde se invoca +Si depuramos y ponemos un breakpoint justo donde se invoca a _react.useState_, otro en el render y otro dentro del código de _useEffect_ podemos ver que se llaman en el siguiente orden: - Primero el _useState_ @@ -94,16 +95,16 @@ a ejecutar el código… **React.useEffect** -En su primer parametro un código que puede contener sideffects +En su primer parámetro un código que puede contener sideffects (una llamada a servidor, un setTimeout...). -Si no le informamos más parametros, esta función se ejecutara siempre -despues de cada render. +Si no le informamos más parámetros, esta función se ejecutará siempre +después de cada render. Esto no está mal, pero mucha veces nos hace falta acotar la ejecución -de cierto código (ejecutate sólo después del primer render del componente, -ejecutate sólo antes ciertas condiciones), por ejemplo podríamos decirle -al código que se ejecutará sólo cuando cambiará la propiedad _username_ +de cierto código (ejecútate sólo después del primer render del componente, +ejecútate sólo antes ciertas condiciones), por ejemplo podríamos decirle +al código que se ejecutará sólo cuando cambie la propiedad _username_ ```tsx React.useEffect(() => { @@ -112,24 +113,24 @@ React.useEffect(() => { ``` Este ejemplo sería un poco tonto porque estamos modificando _username_ dentro -del propio _useEffect_ se metería en un bucle infinito. +del propio \_useEffect, por lo que se metería en un bucle infinito. Un tema interesante: -- Hemos visto que si no informamos el segundo parametro no para de ejecutarse - despues de cada render. +- Hemos visto que si no informamos el segundo parámetro no para de ejecutarse + después de cada render. -- También que si informamos una lista de valores como segundo parametro +- También que si informamos una lista de valores como segundo parámetro se ejecuta cuando estos valores cambian. Peeero ¿Y si informamos esa lista como vacía? Si hacemos esto, el código dentro del useEffect se ejecutará la primera vez (después del primer renderizado) -y no volvera a ejecutarse más ya que le estamos diciendo que no depende de ningún -valor de las propiedades o del estado, de esta manera no volverás a ejecutarse +y no volverá a ejecutarse más ya que le estamos diciendo que no depende de ningún +valor de las propiedades o del estado, de esta manera no volverá a ejecutarse (Para los que ya hayáis trabajado antes con React esto se parece al componentDidMount de los componentes de clase de React). -Para cerrar este ejemplo vamos a simular una llamada asíncrono utilizando +Para cerrar este ejemplo vamos a simular una llamada asíncrona utilizando _setTimeout_ ```diff diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/app.tsx b/04-frameworks/01-react/03-react-hooks/03-component-mount/src/app.tsx similarity index 100% rename from 04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/app.tsx rename to 04-frameworks/01-react/03-react-hooks/03-component-mount/src/app.tsx diff --git a/04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/03-component-mount/src/demo.tsx similarity index 100% rename from 04-frameworks/01-react/03-react-hooks/03-component-did-onload/src/demo.tsx rename to 04-frameworks/01-react/03-react-hooks/03-component-mount/src/demo.tsx diff --git a/04-frameworks/01-react/02-base/03-webpack-react/src/index.tsx b/04-frameworks/01-react/03-react-hooks/03-component-mount/src/index.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/03-webpack-react/src/index.tsx rename to 04-frameworks/01-react/03-react-hooks/03-component-mount/src/index.tsx diff --git a/04-frameworks/01-react/02-base/02-webpack-boiler/src/styles.css b/04-frameworks/01-react/03-react-hooks/03-component-mount/src/styles.css similarity index 100% rename from 04-frameworks/01-react/02-base/02-webpack-boiler/src/styles.css rename to 04-frameworks/01-react/03-react-hooks/03-component-mount/src/styles.css diff --git a/04-frameworks/01-react/03-react-hooks/03-component-mount/tsconfig.json b/04-frameworks/01-react/03-react-hooks/03-component-mount/tsconfig.json new file mode 100644 index 000000000..a057cea1d --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/03-component-mount/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/03-react-hooks/03-component-mount/vite.config.ts b/04-frameworks/01-react/03-react-hooks/03-component-mount/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/03-component-mount/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/Readme.md b/04-frameworks/01-react/03-react-hooks/04-component-unmount/Readme.md similarity index 78% rename from 04-frameworks/01-react/03-react-hooks/04-component_unmount/Readme.md rename to 04-frameworks/01-react/03-react-hooks/04-component-unmount/Readme.md index bdda788ad..efa2dbc8e 100644 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/Readme.md @@ -1,8 +1,8 @@ # 04 Component unmount -## Resume +## Summary -This example takes the _03-component-dom-onload_ example as starting point. +This example takes the _03-component-mount_ example as a starting point. In this example we are going to see how to free resources when we unmount a DOM component. @@ -16,9 +16,9 @@ npm install - We are going to create a component that shows or hides a text depending on a boolean flag. -Overwrite _demo.js_ file with the following content. +Overwrite _demo.tsx_ file with the following content. -_./src/demo.js_ +_./src/demo.tsx_ ```jsx import React from "react"; @@ -76,10 +76,10 @@ export const MyComponent = () => { }; ``` -- Now we got a childr component that is mounted / unmounted from the dom when a user clicks on a button. +- Now we got a child component that is mounted / unmounted from the DOM when an user clicks on a button. -How could we do to display a message on the console -browser when the child component will be mounted? +How could display a message in the browser console +when the child component is mounted? If we remember the previous example, we can use _React.useEffect_. Before continue just give a try by yourself. @@ -97,10 +97,10 @@ export const MyChildComponent = () => { }; ``` -- Now comes the interesting part, what if we want to show a message on the browser console when the component is unmounted from the DOM? Just +- Now it comes the interesting part, what if we want to show a message in the browser console when the component is unmounted from the DOM? Just by adding in the return value of that _useEffect_ a function that will be called when the component is unmounted. -_./src/demo.js_ +_./src/demo.tsx_ ```diff export const MyChildComponent = () => { @@ -110,7 +110,7 @@ export const MyChildComponent = () => { }, []); ``` -Any useful scenarios? Imagine that you open a connection to a websocket and you want to close it when the user hides the component, how do you free resources in a proper way? By using this approach. +Any useful scenarios? Imagine you open a connection to a websocket and you want to close it when the component is unmounted, how do you free resources in a proper way? By using this approach. # About Basefactor + Lemoncode diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/Readme_es.md b/04-frameworks/01-react/03-react-hooks/04-component-unmount/Readme_es.md similarity index 88% rename from 04-frameworks/01-react/03-react-hooks/04-component_unmount/Readme_es.md rename to 04-frameworks/01-react/03-react-hooks/04-component-unmount/Readme_es.md index be29ee2ad..f02b5d6c3 100644 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/Readme_es.md @@ -2,7 +2,7 @@ ## Resumen -Este ejemplo toma como punto de partida el ejemplo _03-component-dom-onload_. +Este ejemplo toma como punto de partida el ejemplo _03-component-mount_. En este ejemplo vamos a ver como liberar recursos cuando desmontamos un componente del DOM. @@ -39,10 +39,10 @@ _./src/demo.tsx_ ```diff return ( <> - {visible &&

Hello

} + + {visible &&

Hello

} ); ``` @@ -61,22 +61,22 @@ export const MyComponent = () => { return ( <> -- {visible &&

Hello

} -+ {visible && } +- {visible &&

Hello

} ++ {visible && } ); }; ``` -- Ahora tenemos un componente hijo que pinchando en un botón +- Ahora tenemos un componente hijo que clicando en un botón se monta o desmonta del dom. ¿Cómo podríamos hacer para mostrar un mensaje por la consola del navegador cuando se montara el componente hijo? -Si recordamos el ejemplo anterior,sería con _React.useEffect_ +Si recordamos el ejemplo anterior, sería con _React.useEffect_ ¿Te animas a intentarlo? Dale a la pausa al video y ponte :). Podríamos hacer algo así como: @@ -93,9 +93,9 @@ export const MyChildComponent = () => { }; ``` -- Ahora viene la parte interesante, y si queremos mostrar un mensaje - por la console del navegador cuando el componente se desmonta del DOM? - En la misma función que ponemos como primer parametro devolvemos +- Ahora viene la parte interesante, ¿Y si queremos mostrar un mensaje + por la consola del navegador cuando el componente se desmonta del DOM? + En la misma función que ponemos como primer parámetro devolvemos la función de "limpieza"... _useEffect_ se va a guardar esa función hasta que desmonte el DOM para invocarla: @@ -107,7 +107,7 @@ export const MyChildComponent = () => { }, []); ``` -¿Para que me puede servir esto? Imaginate que abres una conexión a un websocket +¿Para que me puede servir esto? Imagínate que abres una conexión a un websocket y quieres cerrarla cuando el usuario oculte el componente, ¿ cómo liberas recursos de forma ordenada? Aquí lo tienes. diff --git a/04-frameworks/01-react/03-react-hooks/04-component-unmount/index.html b/04-frameworks/01-react/03-react-hooks/04-component-unmount/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/04-component-unmount/package.json b/04-frameworks/01-react/03-react-hooks/04-component-unmount/package.json new file mode 100644 index 000000000..9ee970f00 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/package.json @@ -0,0 +1,23 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0" + } +} diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/app.tsx b/04-frameworks/01-react/03-react-hooks/04-component-unmount/src/app.tsx similarity index 100% rename from 04-frameworks/01-react/03-react-hooks/04-component_unmount/src/app.tsx rename to 04-frameworks/01-react/03-react-hooks/04-component-unmount/src/app.tsx diff --git a/04-frameworks/01-react/03-react-hooks/04-component-unmount/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/04-component-unmount/src/demo.tsx new file mode 100644 index 000000000..622ae6765 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/src/demo.tsx @@ -0,0 +1,42 @@ +import React from "react"; + +export const MyChildComponent = () => { + const [count, setCount] = React.useState(0); + + React.useEffect(() => { + console.log("Componente se monta"); + return () => console.log("Componente se desmonta"); + }, []); + + React.useEffect(() => { + console.log("body - count just changed", count); + return () => + console.log("cleanupFunction - count is about to change", count); + }, [count]); + + return ( + <> +

Count is {count}

+ + + ); +}; + +export const MyComponent = () => { + const [visible, setVisible] = React.useState(false); + + return ( + <> + + {visible && } + + ); +}; diff --git a/04-frameworks/01-react/02-base/04-list-users/src/index.tsx b/04-frameworks/01-react/03-react-hooks/04-component-unmount/src/index.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/04-list-users/src/index.tsx rename to 04-frameworks/01-react/03-react-hooks/04-component-unmount/src/index.tsx diff --git a/04-frameworks/01-react/02-base/03-webpack-react/src/styles.css b/04-frameworks/01-react/03-react-hooks/04-component-unmount/src/styles.css similarity index 100% rename from 04-frameworks/01-react/02-base/03-webpack-react/src/styles.css rename to 04-frameworks/01-react/03-react-hooks/04-component-unmount/src/styles.css diff --git a/04-frameworks/01-react/03-react-hooks/04-component-unmount/tsconfig.json b/04-frameworks/01-react/03-react-hooks/04-component-unmount/tsconfig.json new file mode 100644 index 000000000..a057cea1d --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/03-react-hooks/04-component-unmount/vite.config.ts b/04-frameworks/01-react/03-react-hooks/04-component-unmount/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/04-component-unmount/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/.babelrc b/04-frameworks/01-react/03-react-hooks/04-component_unmount/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/package.json b/04-frameworks/01-react/03-react-hooks/04-component_unmount/package.json deleted file mode 100644 index 50e9c4ccc..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/package.json +++ /dev/null @@ -1,39 +0,0 @@ -{ - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" - }, - "author": "", - "license": "ISC", - "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" - }, - "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" - } -} diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/demo.tsx deleted file mode 100644 index f57ca7bf4..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/demo.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import React from "react"; - -export const MyChildComponent = () => { - React.useEffect(() => { - console.log("El componente se acaba de montar en el DOM"); - - return () => console.log("El componente se acaba de desmontar del DOM"); - }, []); - - return

Hello form child component

; -}; - -export const MyComponent = () => { - const [visible, setVisible] = React.useState(false); - - return ( - <> - {visible && } - - - ); -}; diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/index.html b/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
- - diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/styles.css b/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/styles.css deleted file mode 100644 index 74dc08fbb..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/src/styles.css +++ /dev/null @@ -1,3 +0,0 @@ -.my-text { - color: blue; -} diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/tsconfig.json b/04-frameworks/01-react/03-react-hooks/04-component_unmount/tsconfig.json deleted file mode 100644 index 3312b5f1e..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, - "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, - "skipLibCheck": true, - "esModuleInterop": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} diff --git a/04-frameworks/01-react/03-react-hooks/04-component_unmount/webpack.config.js b/04-frameworks/01-react/03-react-hooks/04-component_unmount/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/04-component_unmount/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/.babelrc b/04-frameworks/01-react/03-react-hooks/05-component-update-render/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme.md b/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme.md index 567548c0a..d2c485828 100644 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme.md @@ -1,8 +1,8 @@ # 05 Component update render -## Resume +## Summary -We will take as starting point sample \_04-component-dom-unmount. +We will take as starting point sample \_04-component-unmount. In this example we will check how to use React.useEffect in order to execute a given code right after each render. @@ -59,12 +59,12 @@ const MyChildComponent = () => { }; ``` -- Now comes the interesting part: by calling _React.useEffect_ without a second +- Now it comes the interesting part: by calling _React.useEffect_ without a second parameter, the code inside _useEffect_ will be triggered right when the component is just mounted and on any update (clean up function will be called right before the effect is triggered again). -_./src/demo.js_ +_./src/demo.tsx_ ```diff const MyChildComponent = () => { @@ -95,9 +95,6 @@ React.useEffect(() => { }); ``` -- If we start the project and open the browser console we can check the - expected behavior. - # About Basefactor + Lemoncode We are an innovating team of Javascript experts, passionate about turning your ideas into robust products. diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme_es.md b/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme_es.md index 3055849a7..53a9c1dfe 100644 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/Readme_es.md @@ -2,7 +2,7 @@ ## Resumen -Este ejemplo toma como punto de partida el ejemplo \_04-component-dom-unmount. +Este ejemplo toma como punto de partida el ejemplo \_04-component-unmount. En este ejemplo vamos a ver como usar React.useEffect para ejecutar un código justo después de cada renderizado. @@ -15,7 +15,7 @@ un código justo después de cada renderizado. npm install ``` -- Vamos abrir el fichero _demo.js_ y crear el ejemplo de un componente +- Vamos abrir el fichero _demo.tsx_ y crear el ejemplo de un componente padre y un hijo que se muestra dependiendo de una condición booleana. ```tsx @@ -26,10 +26,10 @@ export const MyComponent = () => { return ( <> - {visible && } + {visible && } ); }; @@ -59,7 +59,7 @@ const MyChildComponent = () => { ``` - Ahora viene la parte interesante, vamos a llamar a _React.useEffect_ sólo - informando el primer parametro. + informando el primer parámetro. ```diff const MyChildComponent = () => { @@ -78,7 +78,7 @@ const MyChildComponent = () => { - Si ejecutamos podemos ver que este código se ejecuta después de cada renderizado del componente. -- También podemos añadir una función para liberar recursos justo antes de que se ejecute el siguiente render. +- También podemos añadir una función de limpieza (clean-up function) para liberar recursos justo antes de que se ejecute el siguiente render. ```diff React.useEffect(() => { @@ -93,8 +93,53 @@ React.useEffect(() => { - Si ejecutamos podemos ver como se invocan las dos funciones. -```bash -npm start +Como hemos visto, si no pasamos un segundo argumento a _useEffect_, el effect o callback que pasamos por primer parámetro se ejecutará en cada re-ejecución. Sin embargo, si queremos controlar cuándo se ejecuta el efecto y su función de limpieza, debemos indicar explícitamente las dependencias en el segundo parámetro. + +Para comprobar este comportamiento, eliminamos el useEffect del ejemplo anterior y creamos uno nuevo que se dispare cada vez que cambie cualquier valor dentro de _userInfo_: + +```diff +const MyChildComponent = () => { + const [userInfo, setUserInfo] = React.useState({ + name: "John", + lastname: "Doe" + }); + +- React.useEffect(() => { +- console.log("A. Called right after every render"); +- return () => console.log("B. Cleanup function called after every render"); +- }); + ++ React.useEffect(() => { ++ console.log("Effect ran: component rendered with userInfo:", userInfo); ++ return () => ++ console.log("Cleanup before running new effect, userInfo was", userInfo); ++ }, [userInfo]); +``` + +Independientemente de qué propiedad modifiquemos, el efecto y su función de limpieza se ejecutarán. Esto ocurre porque hemos definido como dependencia al estado completo _userInfo_. + +Si queremos diferenciar la ejecución del efecto en función de propiedades concretas, basta con especificar directamente la propiedad dentro del array de dependencias: + +```diff +const MyChildComponent = () => { + const [userInfo, setUserInfo] = React.useState({ + name: "John", + lastname: "Doe" + }); + + React.useEffect(() => { +- console.log("Effect ran: component rendered with userInfo:", userInfo); ++ console.log(`Effect ran: component rendered with name: ${userInfo.name}`); ++ return () => +- console.log("Cleanup before running new effect, userInfo was", userInfo); ++ console.log(`Cleanup before running new effect, name: ${userInfo.name}`); ++ }, [userInfo.name]); + ++ React.useEffect(() => { ++ console.log(`Effect ran: component rendered with lastname: ${userInfo.lastname}`); ++ return () => ++ console.log(`Cleanup before running new effect, lastname: ${userInfo.lastname}`); ++ }, [userInfo.lastname]); ``` # ¿Te apuntas a nuestro máster? diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/index.html b/04-frameworks/01-react/03-react-hooks/05-component-update-render/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/package.json b/04-frameworks/01-react/03-react-hooks/05-component-update-render/package.json index 50e9c4ccc..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/package.json +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/package.json @@ -1,39 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/demo.tsx index a346bfe9a..b0d80ae6b 100644 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/demo.tsx +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/demo.tsx @@ -5,10 +5,10 @@ export const MyComponent = () => { return ( <> - {visible && } + {visible && } ); }; @@ -20,10 +20,20 @@ const MyChildComponent = () => { }); React.useEffect(() => { - console.log("A. Called right after every render"); + console.log(`Effect ran: component rendered with name: ${userInfo.name}`); + return () => + console.log(`Cleanup before running new effect, name: ${userInfo.name}`); + }, [userInfo.name]); - return () => console.log("B. Cleanup function called after every render"); - }); + React.useEffect(() => { + console.log( + `Effect ran: component rendered with lastname: ${userInfo.lastname}` + ); + return () => + console.log( + `Cleanup before running new effect, lastname: ${userInfo.lastname}` + ); + }, [userInfo.lastname]); return (
diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/index.html b/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
- - diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/tsconfig.json b/04-frameworks/01-react/03-react-hooks/05-component-update-render/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/vite.config.ts b/04-frameworks/01-react/03-react-hooks/05-component-update-render/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/05-component-update-render/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/05-component-update-render/webpack.config.js b/04-frameworks/01-react/03-react-hooks/05-component-update-render/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/05-component-update-render/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/.babelrc b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme.md b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme.md index b7789b8e5..27078f513 100644 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme.md @@ -1,6 +1,6 @@ # 06 Ajax field change -## Resume +## Summary This example takes as a starting point the example \ \_05-component-update-render. @@ -16,7 +16,7 @@ As a bonus, we will check how to use Debounce (wait a little until the user stop npm install ``` -- Let's open the _demo.js_, and let's add an entry in the state that stores the current search filter, and another state in which we +- Let's open the _demo.tsx_, and let's add an entry in the state that stores the current search filter, and another state in which we are going to store a list of users. _./src/demo.tsx_ diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme_es.md b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme_es.md index 6e0d253f3..4fecef354 100644 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/Readme_es.md @@ -21,7 +21,7 @@ así llamadas innecesarias). npm install ``` -- Vamos abrir el fichero _demo.js_ y vamos añadir una entrada en el +- Vamos abrir el fichero _demo.tsx_ y vamos añadir una entrada en el estado que almacene el filtro actual de busqueda, y otra en la que almacene una lista de usuarios. diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/index.html b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
+ + + diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/package.json b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/package.json index d434b896c..cb10a2306 100644 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/package.json +++ b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/package.json @@ -1,40 +1,24 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "use-debounce": "^10.0.5" } } diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/src/index.html b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
- - diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/tsconfig.json b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/vite.config.ts b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/webpack.config.js b/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/06-ajax-field-change/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/.babelrc b/04-frameworks/01-react/03-react-hooks/07-custom-hook/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/Readme.md b/04-frameworks/01-react/03-react-hooks/07-custom-hook/Readme.md index b7cc0439c..ac3763b4f 100644 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/07-custom-hook/Readme.md @@ -1,8 +1,8 @@ # 07 Custom hooks -## Resume +## Summary -This example takes as its starting point the \ _06-ajax-field-change example. +This example takes as its starting point the \ \_06-ajax-field-change example. Hooks are cool, but our functional component seems to get cluttered, is there a way to extract functionality outside the functional component? @@ -31,13 +31,13 @@ export const MyComponent = () => { // Load full list when the component gets mounted and filter gets updated React.useEffect(() => { fetch(`https://jsonplaceholder.typicode.com/users?name_like=${filter}`) - .then(response => response.json()) - .then(json => setUserCollection(json)); + .then((response) => response.json()) + .then((json) => setUserCollection(json)); }, [filter]); return (
- setFilter(e.target.value)} /> + setFilter(e.target.value)} />
    {userCollection.map((user, index) => (
  • {user.name}
  • @@ -53,7 +53,7 @@ export const MyComponent = () => { A. Encapsulating as well the _UseEffect_ -_./src/demo.js_ +_./src/demo.tsx_ ```diff import React from "react"; diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/index.html b/04-frameworks/01-react/03-react-hooks/07-custom-hook/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/07-custom-hook/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/package.json b/04-frameworks/01-react/03-react-hooks/07-custom-hook/package.json index d434b896c..cb10a2306 100644 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/package.json +++ b/04-frameworks/01-react/03-react-hooks/07-custom-hook/package.json @@ -1,40 +1,24 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "use-debounce": "^10.0.5" } } diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/app.tsx b/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/app.tsx index bc2cf5bd8..363d30bfa 100644 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/app.tsx +++ b/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/app.tsx @@ -3,4 +3,4 @@ import { MyComponent } from "./demo"; export const App = () => { return ; -}; +}; \ No newline at end of file diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/index.html b/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/tsconfig.json b/04-frameworks/01-react/03-react-hooks/07-custom-hook/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/07-custom-hook/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/vite.config.ts b/04-frameworks/01-react/03-react-hooks/07-custom-hook/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/07-custom-hook/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/07-custom-hook/webpack.config.js b/04-frameworks/01-react/03-react-hooks/07-custom-hook/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/07-custom-hook/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/.babelrc b/04-frameworks/01-react/03-react-hooks/08-pure-component/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/08-pure-component/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/Readme_es.md b/04-frameworks/01-react/03-react-hooks/08-pure-component/Readme_es.md index 37180b4b8..fa2004f5d 100644 --- a/04-frameworks/01-react/03-react-hooks/08-pure-component/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/08-pure-component/Readme_es.md @@ -17,7 +17,7 @@ Vamos a ello. npm install ``` -- Vamos a pegar un ejemplo en _demo.js_, este código va tener dos +- Vamos a pegar un ejemplo en _demo.tsx_, este código va tener dos valores editables: _name_ y _lastname_ y vamos a tener un control hijo que sólo va a mostrar el _name_ (de hecho este componente sólo pedirá el campo nombre en las propiedades). diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/index.html b/04-frameworks/01-react/03-react-hooks/08-pure-component/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/08-pure-component/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/package.json b/04-frameworks/01-react/03-react-hooks/08-pure-component/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/08-pure-component/package.json +++ b/04-frameworks/01-react/03-react-hooks/08-pure-component/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/src/index.html b/04-frameworks/01-react/03-react-hooks/08-pure-component/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/08-pure-component/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/tsconfig.json b/04-frameworks/01-react/03-react-hooks/08-pure-component/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/08-pure-component/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/08-pure-component/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/vite.config.ts b/04-frameworks/01-react/03-react-hooks/08-pure-component/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/08-pure-component/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/08-pure-component/webpack.config.js b/04-frameworks/01-react/03-react-hooks/08-pure-component/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/08-pure-component/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/.babelrc b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/index.html b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/package.json b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/package.json +++ b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/src/index.html b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/tsconfig.json b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/vite.config.ts b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/webpack.config.js b/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/09-pure-component-callback/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/.babelrc b/04-frameworks/01-react/03-react-hooks/10-use-reducer/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/10-use-reducer/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/Readme.md b/04-frameworks/01-react/03-react-hooks/10-use-reducer/Readme.md index 108fa47e7..bfb699c6d 100644 --- a/04-frameworks/01-react/03-react-hooks/10-use-reducer/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/10-use-reducer/Readme.md @@ -1,6 +1,6 @@ # 10 useReducer -## Resume +## Summary This example takes as a starting point _09-pure-component-callback_. diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/index.html b/04-frameworks/01-react/03-react-hooks/10-use-reducer/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/10-use-reducer/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/package.json b/04-frameworks/01-react/03-react-hooks/10-use-reducer/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/10-use-reducer/package.json +++ b/04-frameworks/01-react/03-react-hooks/10-use-reducer/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/src/index.html b/04-frameworks/01-react/03-react-hooks/10-use-reducer/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/10-use-reducer/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/tsconfig.json b/04-frameworks/01-react/03-react-hooks/10-use-reducer/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/10-use-reducer/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/10-use-reducer/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/vite.config.ts b/04-frameworks/01-react/03-react-hooks/10-use-reducer/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/10-use-reducer/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/10-use-reducer/webpack.config.js b/04-frameworks/01-react/03-react-hooks/10-use-reducer/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/10-use-reducer/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/.babelrc b/04-frameworks/01-react/03-react-hooks/11-use-context/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/Readme.md b/04-frameworks/01-react/03-react-hooks/11-use-context/Readme.md index d14673dd6..ac484cd7f 100644 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/Readme.md @@ -1,6 +1,6 @@ # 11 useContext -## Resume +## Summary This example takes the _10-use-reducer_ example as a starting point. @@ -36,22 +36,22 @@ userGlobalDAta.login = "john"; This approach that we could first try to defend (it is flat ES6, so React account only takes care of the UI...), it brings us several problems: -- What if the value of _userGlobalData.login_ changes and I have multiple parts of the application they are using it? How do I notify you of the change? Would have to play pulling and collecting global events to go repainting. +- What if the value of _userGlobalData.login_ changes and I have multiple parts of the application they are using it? How do I notify you of the change? Would have to play pulling and collecting global events to go repainting. - And now to finish, if I want to use Server Side Rendering (that is, pregenerate the pages on the server to serve HTML, this is good for example for have a good SEO), we would have a big problem ... communicating vessels, all the requests would share the same static variables. React incorporates a very powerful mechanism, it is called ** Context ** - - The ** Context ** allows me to share data between components without going through the props. - The Context lives within a React component, with which it is integrated into the React one-way flow, that is, any change you make to it makes updates to be triggered automatically. - I can place the Context at the level I want in the component tree, that is, I can make that data available at the full application level or for example a window containing several tabs. - And to all this we have to add that React incorporates a hook called -_useContext_ which makes using it very easy. +_use_ which makes using it very easy. + +**In previous versions to react 19, use _usecontext_ to consume contexts** Let's see how this works. @@ -99,13 +99,36 @@ const MyContext = React.createContext({ + const [username, setUsername] = React.useState("John Doe"); + + return ( -+ ++ + {props.children} -+ ++ + ); + }; ``` +In previous versions to react 19, the provider is only available as a method inside the context. From react 19, +this is still possible, but only as legacy. We prefer to use the new approach. + +```jsx +import React from "react"; + +const MyContext = React.createContext({ + username: "", + setUsername: () => {}, +}); + +export const MyContextProvider = (props) => { + const [username, setUsername] = React.useState("John Doe"); + + return ( + // MyContext.Provider is legacy + + {props.children} + + ); +}; +``` + Check out what we have here: - We have a component that provides state to our context. @@ -158,7 +181,7 @@ _./src/demo.tsx_ ```diff export const MyComponent = () => { -+ const myContext = React.useContext(MyContext); ++ const myContext = React.use(MyContext); return ( <> @@ -168,6 +191,7 @@ export const MyComponent = () => { ) } ``` + - If we execute the example we can see it working: ```bash diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/Readme_es.md b/04-frameworks/01-react/03-react-hooks/11-use-context/Readme_es.md index 41e333dfb..2f79918aa 100644 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/Readme_es.md @@ -69,7 +69,9 @@ React incorpora un mecanismo muy potente, se llama **Context** o de por ejemplo una ventana que contenga varios tabs. Y a todo esto tenemos que añadirle que React incorpora un hook que se llama -_useContext_ que hace que usarlo sea muy facil. +_use_ que hace que usarlo sea muy facil. + +**En versiones anteriores a la 19, usar _usecontext_ para consumir contextos** Vamos a ver como funciona esto. @@ -122,13 +124,36 @@ const MyContext = React.createContext({ + const [username, setUsername] = React.useState("John Doe"); + + return ( -+ ++ + {props.children} -+ ++ + ); + }; ``` +En versiones anteriores de react 19, el provider está disponible como método dentro de MyContext. En la versión 19 +sigue siendo posible usarlo, aunque se considera legacy. Nosotros nos quedamos con la nueva versión. + +```jsx +import React from "react"; + +const MyContext = React.createContext({ + username: "", + setUsername: () => {}, +}); + +export const MyContextProvider = (props) => { + const [username, setUsername] = React.useState("John Doe"); + + return ( + // MyContext.Provider is legacy + + {props.children} + + ); +}; +``` + Fijate lo que tenemos aqui: - Tenemos un componente que provee de estado a nuestro contexto. @@ -181,7 +206,7 @@ hay debajo del contextprovider lo pinta tal cual ese componente. ```diff export const MyComponent = () => { -+ const myContext = React.useContext(MyContext); ++ const myContext = React.use(MyContext); return ( <> diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/index.html b/04-frameworks/01-react/03-react-hooks/11-use-context/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/package.json b/04-frameworks/01-react/03-react-hooks/11-use-context/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/package.json +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/11-use-context/src/demo.tsx index 64134de6c..766e3c846 100644 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/src/demo.tsx +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/src/demo.tsx @@ -14,9 +14,7 @@ export const MyContextProvider = (props) => { const [username, setUsername] = React.useState("John Doe"); return ( - - {props.children} - + {props.children} ); }; diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/src/index.html b/04-frameworks/01-react/03-react-hooks/11-use-context/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/tsconfig.json b/04-frameworks/01-react/03-react-hooks/11-use-context/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/vite.config.ts b/04-frameworks/01-react/03-react-hooks/11-use-context/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/11-use-context/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/11-use-context/webpack.config.js b/04-frameworks/01-react/03-react-hooks/11-use-context/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/11-use-context/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/.babelrc b/04-frameworks/01-react/03-react-hooks/12-set-state-func/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/12-set-state-func/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/Readme.md b/04-frameworks/01-react/03-react-hooks/12-set-state-func/Readme.md index 7c723e258..0f1b944be 100644 --- a/04-frameworks/01-react/03-react-hooks/12-set-state-func/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/12-set-state-func/Readme.md @@ -1,6 +1,6 @@ # 12 set state func -## Resume +## Summary This example takes the _11-use-context_ example as a starting point. diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/index.html b/04-frameworks/01-react/03-react-hooks/12-set-state-func/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/12-set-state-func/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/package.json b/04-frameworks/01-react/03-react-hooks/12-set-state-func/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/12-set-state-func/package.json +++ b/04-frameworks/01-react/03-react-hooks/12-set-state-func/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/src/index.html b/04-frameworks/01-react/03-react-hooks/12-set-state-func/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/12-set-state-func/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/tsconfig.json b/04-frameworks/01-react/03-react-hooks/12-set-state-func/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/12-set-state-func/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/12-set-state-func/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/vite.config.ts b/04-frameworks/01-react/03-react-hooks/12-set-state-func/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/12-set-state-func/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/12-set-state-func/webpack.config.js b/04-frameworks/01-react/03-react-hooks/12-set-state-func/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/12-set-state-func/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/.babelrc b/04-frameworks/01-react/03-react-hooks/13-async-closure/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/13-async-closure/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/index.html b/04-frameworks/01-react/03-react-hooks/13-async-closure/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/13-async-closure/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/package.json b/04-frameworks/01-react/03-react-hooks/13-async-closure/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/13-async-closure/package.json +++ b/04-frameworks/01-react/03-react-hooks/13-async-closure/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/src/index.html b/04-frameworks/01-react/03-react-hooks/13-async-closure/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/13-async-closure/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/tsconfig.json b/04-frameworks/01-react/03-react-hooks/13-async-closure/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/13-async-closure/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/13-async-closure/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/vite.config.ts b/04-frameworks/01-react/03-react-hooks/13-async-closure/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/13-async-closure/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/13-async-closure/webpack.config.js b/04-frameworks/01-react/03-react-hooks/13-async-closure/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/13-async-closure/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/.babelrc b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/Readme_es.md b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/Readme_es.md index c59aeaf25..c5164ace8 100644 --- a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/Readme_es.md @@ -12,7 +12,7 @@ vamos a usarlo para acceder a un nodo del dom. npm install ``` -- En _demo.js_ pegamos el siguiente código (fijate que aquí definimos +- En _demo.tsx_ pegamos el siguiente código (fijate que aquí definimos el _useRef_ y lo asociamos en el _div_ container). _./src/demo.tsx_ diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/index.html b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/package.json b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/package.json +++ b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/src/index.html b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/tsconfig.json b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/vite.config.ts b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/webpack.config.js b/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/14-use-ref-dom/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/.babelrc b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/Readme.md b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/Readme.md index ba8d8c3e4..e96333d34 100644 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/Readme.md @@ -12,19 +12,6 @@ We are going to implement a customer satisfaction widget, based on smily faces, npm install ``` -- We have to make a slight change in this example in our _webpack.config.js_ - -```diff -... - { - test: /\.(png|jpg)$/, - exclude: /node_modules/, -- loader: "url-loader", -+ type: "asset/resource", - }, -... -``` - - Let's copy the five smiley faces (you can copy them from the sample implementation in github) into the route _src/assets_. - Let's add the following content into the _src/styles.css_ css file to add the smileys styles: diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/index.html b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/package.json b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/package.json +++ b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.html b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.tsx b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.tsx +++ b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/tsconfig.json b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/vite.config.ts b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/webpack.config.js b/04-frameworks/01-react/03-react-hooks/15-memo-predicate/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/15-memo-predicate/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/.babelrc b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/index.html b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/package.json b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/package.json +++ b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.html b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.tsx b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.tsx +++ b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/tsconfig.json b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/vite.config.ts b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/webpack.config.js b/04-frameworks/01-react/03-react-hooks/16-use-debug-value/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/16-use-debug-value/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/.babelrc b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/index.html b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
    + + + diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/package.json b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/package.json +++ b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/demo.tsx index 1ce9a88cb..7c2886cc9 100644 --- a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/demo.tsx +++ b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/demo.tsx @@ -4,7 +4,7 @@ import React from "react"; function useWhyDidYouUpdate(name, props) { // Get a mutable ref object where we can store props ... // ... for comparison next time this hook runs. - const previousProps = React.useRef(); + const previousProps = React.useRef(null); React.useEffect(() => { if (previousProps.current) { diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/index.html b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
    - - diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/tsconfig.json b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/vite.config.ts b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/webpack.config.js b/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/17-why-did-you-update/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/Readme.md b/04-frameworks/01-react/03-react-hooks/18-use-promise/Readme.md new file mode 100644 index 000000000..27078f513 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/Readme.md @@ -0,0 +1,123 @@ +# 06 Ajax field change + +## Summary + +This example takes as a starting point the example \ \_05-component-update-render. + +Let's simulate a real scenario, we have a search result list(we read this from a server source), and each time that we enter a change to a filtering input we want to send a request to the server to get the new filtered list and display it. + +As a bonus, we will check how to use Debounce (wait a little until the user stops typing to send the request, saving so unnecessary calls). + +# Steps + +- First we copy the previous example, and do a _npm install_. + +```bash +npm install +``` + +- Let's open the _demo.tsx_, and let's add an entry in the state that stores the current search filter, and another state in which we + are going to store a list of users. + +_./src/demo.tsx_ + +```tsx +import React from "react"; + +export const MyComponent = () => { + const [filter, setFilter] = React.useState(""); + const [userCollection, setUserCollection] = React.useState([]); + + return ( +
    + setFilter(e.target.value)} /> +
      + {userCollection.map((user, index) => ( +
    • {user.name}
    • + ))} +
    +
    + ); +}; +``` + +- Now we want to fire an _ajax request_ every time the user types on the filter input. + +_./src/demo.tsx_ + +```diff +export const MyComponent = () => { + const [filter, setFilter] = React.useState(''); + const [userCollection, setUserCollection] = React.useState([]); + ++ // Load full list when the component gets mounted and filter gets updated ++ React.useEffect(() => { ++ fetch(`https://jsonplaceholder.typicode.com/users?name_like=${filter}`) ++ .then(response => response.json()) ++ .then(json => setUserCollection(json)); ++ }, [filter]); + + return ( +``` + +**BE CAREFUL!!! Typicode** since we are hitting a free rest api it maybe down or asleep, maybe you will have to give some tries :). + +You can try as with other apis as well (you will need to take a look at the documention, some of them return slightly different +response structures). + +https://rickandmortyapi.com/ + +https://swapi.dev/documentation#auth + +```tsx +React.useEffect(() => { + fetch(`https://swapi.dev/api/people?search=${filter}`) + .then((response) => response.json()) + .then((json) => setUserCollection(json.results)); +}, [filter]); +``` + +- If we execute this code we can see that the filtering option works. + +```bash +npm start +``` + +## BONUS + +This is fine, but it isn't optimal, we usually want to trigger the search just when the user has stopped typing to avoid making unnecessary calls. + +We can download a library that implements a custom hook that just implements that behavior: https://github.com/xnimorz/use-debounce + +Using this is a piece of cake: + +```bash +npm install use-debounce --save +``` + +```diff ++ import { useDebounce } from 'use-debounce'; + +export const MyComponent = () => { + const [filter, setFilter] = React.useState(""); ++ const [debouncedFilter] = useDebounce(filter, 500); + const [userCollection, setUserCollection] = React.useState([]); + + // Load full list when the component gets mounted and filter gets updated + React.useEffect(() => { + fetch(`https://jsonplaceholder.typicode.com/users?name_like=${filter}`) + .then((response) => response.json()) + .then((json) => setUserCollection(json)); +- }, [filter]); ++ }, [debouncedFilter]); +``` + +# About Basefactor + Lemoncode + +We are an innovating team of Javascript experts, passionate about turning your ideas into robust products. + +[Basefactor, consultancy by Lemoncode](http://www.basefactor.com) provides consultancy and coaching services. + +[Lemoncode](http://lemoncode.net/services/en/#en-home) provides training services. + +For the LATAM/Spanish audience we are running an Online Front End Master degree, more info: http://lemoncode.net/master-frontend diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/Readme_es.md b/04-frameworks/01-react/03-react-hooks/18-use-promise/Readme_es.md new file mode 100644 index 000000000..2ba616fd0 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/Readme_es.md @@ -0,0 +1,278 @@ +# 06 Use hook + +Vamos a ver el nuevo hook _use_, introducido en la versión 19 de react. En este ejemplo vamos a usar el hook para consumir datos que recibimos de manera asíncrona, haciendo una petición al servidor. + +## Punto de Partida + +Este ejemplo parte del ejercicio \_06-ajax-field-change. Si no tienes el código a mano te lo dejamos por aquí. + +_./src/demo.tsx_ + +```tsx +import React from "react"; + +export const MyComponent = () => { + const [filter, setFilter] = React.useState(""); + const [userCollection, setUserCollection] = React.useState([]); + + React.useEffect(() => { + fetch(`https://jsonplaceholder.typicode.com/users?name_like=${filter}`) + .then((response) => response.json()) + .then((json) => setUserCollection(json)); + }, [filter]); + + return ( +
    + setFilter(e.target.value)} /> +
      + {userCollection.map((user, index) => ( +
    • {user.name}
    • + ))} +
    +
    + ); +}; +``` + +_./src/app.tsx_ + +```tsx +import React from "react"; +import { MyComponent } from "./demo"; + +export const App = () => { + return ; +}; +``` + +## Paso a Paso + +Primero hacemos un _npm install_. + +```bash +npm install +``` + +Lo primero que necesitamos es una llamada asíncrona. Vamos a crearnos por el momento una llamada que no ataque a ningún servidor, sino que simplemente devuelva usuarios mockeados. Introducimos además un log para ver cuantas veces se ejecuta la función. + +En _./src/demo.tsx_ + +```diff +import React from "react"; + ++ const fetchMockedUsers = async () => { ++ console.log("executed"); ++ const res = await Promise.resolve([{ name: "Test user", id: 1 }]); ++ return res; ++ }; + +export const MyComponent = () => { +``` + +El hook use se va a encargar de gestionar la llamada y de devolvernos el estado, por lo que podemos reemplazar el useState y el useEffect. + +En _./src/demo.tsx_ + +```diff +- import React from "react"; ++ import React, { use } from "react"; + + +export const MyComponent = () => { + const [filter, setFilter] = React.useState(""); ++ const userCollection = use(fetchMockedUsers()) +- const [userCollection, setUserCollection] = React.useState([]); + +- React.useEffect(() => { +- fetch(`https://jsonplaceholder.typicode.com/users?name_like=${filter}`) +- .then((response) => response.json()) +- .then((json) => setUserCollection(json)); +- }, [filter]); + + return ( +``` + +Si levantamos el proyecto, abrimos las _devTools_ y vemos los logs del browser, nos damos cuenta de que hemos entrado en un bucle infinito (el log debe aparecer muchas veces). Esto se debe a como funciona el hook _use_ por dentro y a que nos hemos saltado una regla fundamental establecida por la documentación de React: al hook _use_ hay que pasarle una referencia estable. +Esto se diferencia a lo que hemos hecho dentro de nuestro componente, donde dentro de cada ejecución _fetchMockedUsers()_ crea una nueva referencia en cada re-ejecución, por lo que el componente se va a re-ejecutar infinitas veces. + +Para poder adaptarnos a las condiciones de uso de _use_ esa referencia debe ser estable, por lo que le deberá llegar a nuestro componente como _prop_. De esta manera esa _prop_ no se calculará en cada ejecución. + +Así, nos creamos un componente padre _MyParentComponent_ que wrapee a _MyComponent_. + +- Movemos _fetchMockedUsers_ a este fichero +- Creamos User interface. +- Introducimos _Suspense_, requerido para poder usar _use_. Este componente nos permitirá usar un fallback mientras la llamada está pendiente de resolverse. + +_./src/parent.tsx_ + +```tsx +import React, { Suspense } from "react"; +import { MyComponent } from "./demo"; + +export interface User { + id: number; + name: string; +} + +const fetchMockedUsers = async () => { + console.log("executed"); + const res = await Promise.resolve([{ name: "Test user", id: 1 }]); + return res; +}; + +export const MyParentComponent = () => { + const mockedUsersPromise = fetchMockedUsers(); + return ( + <> + Loading}> + + + + ); +}; +``` + +Actualizamos en _./src/demo.tsx_: + +- Tipamos _MyComponent_ correctamente. +- _MyComponent_ recibe la nueva prop. +- Eliminamos _fetchMockedUsers_. + +```diff +import React, { use } from "react"; ++ import { User } from './parent'; + +- export const fetchMockedUsers = async () => { +- console.log("executed"); +- const res = await Promise.resolve([{ name: "Test user", id: 1 }]); +- return res; +- }; + ++ interface MyComponentProps { ++ userPromise: Promise ++ } + +- export const MyComponent = () => { ++ export const MyComponent: React.FC = ({ userPromise }) => { + const [filter, setFilter] = React.useState(""); +- const userCollection = use(fetchMockedUsers()); ++ const userCollection = use(userPromise); + + return ( +``` + +Reemplazamos en _./src/app.tsx_ + +```diff +import React from "react"; +- import { MyComponent } from "./demo"; ++ import { MyParentComponent } from "./parent"; + +export const App = () => { +- return ; ++ return ; +}; +``` + +Comprobamos que la aplicación funciona. + +Ahora que ya sabemos que no estamos incurriendo en bucles infinitos es seguro sustituir la función mock por la llamada real. Además, al estar interpolando dentro de la llamada _filter_, nos tenemos que traer el estado y el input que lo setea. + +_./src/parent.tsx_ + +```diff +export interface User { + id: number; + name: string; +} + +- const fetchMockedUsers = async () => { +- console.log("executed"); +- const res = await Promise.resolve([{ name: "Test user", id: 1 }]); +- return res; +- }; + ++ const fetchUsers = async (filter): Promise => { ++ const res = await fetch( ++ `https://jsonplaceholder.typicode.com/users?name_like=${filter}` ++ ); ++ return res.json(); ++ }; + +export const MyParentComponent = () => { ++ const [filter, setFilter] = React.useState(""); +- const mockedUsersPromise = fetchMockedUsers(); ++ const usersPromise = fetchUsers(filter); + + return ( + <> ++ setFilter(e.target.value)} /> + Loading}> +- ++ + + + ); +}; +``` + +Eliminamos de _MyComponent_, el estado _filter_ y el input que lo setea: + +_./src/demo.tsx_ + +```diff +export const MyComponent: React.FC = ({ userPromise }) => { +- const [filter, setFilter] = React.useState(""); + const userCollection = use(userPromise); + + return ( +
    +- setFilter(e.target.value)} /> +
      +``` + +Y si quisiéramos implementar el useDebounce? + +- Instalamos la librería _use-debounce_ como dependencia + +```bash +npm i use-debounce +``` + +En _./src/parent.tsx_: + +```diff +import React, { Suspense } from "react"; ++ import { useDebounce } from "use-debounce"; + +(...) + +export const MyParentComponent = () => { + const [filter, setFilter] = React.useState(""); ++ const [debouncedFilter] = useDebounce(filter, 1500); +- const usersPromise = fetchUsers(filter); + ++ const usersPromise = React.useMemo( ++ () => fetchUsers(debouncedFilter), ++ [debouncedFilter] ++ ); + + return ( + <> ++
      Debounced filter: {debouncedFilter}
      + setFilter(e.target.value)} /> + Loading}> +``` + +# ¿Te apuntas a nuestro máster? + +Si te ha gustado este ejemplo y tienes ganas de aprender Front End +guiado por un grupo de profesionales ¿Por qué no te apuntas a +nuestro [Máster Front End Online Lemoncode](https://lemoncode.net/master-frontend#inicio-banner)? Tenemos tanto edición de convocatoria +con clases en vivo, como edición continua con mentorización, para +que puedas ir a tu ritmo y aprender mucho. + +Si lo que te gusta es el mundo del _backend_ también puedes apuntante a nuestro [Bootcamp backend Online Lemoncode](https://lemoncode.net/bootcamp-backend#bootcamp-backend/inicio) + +Y si tienes ganas de meterte una zambullida en el mundo _devops_ +apuntate nuestro [Bootcamp devops online Lemoncode](https://lemoncode.net/bootcamp-devops#bootcamp-devops/inicio) diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/index.html b/04-frameworks/01-react/03-react-hooks/18-use-promise/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
      + + + diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/package.json b/04-frameworks/01-react/03-react-hooks/18-use-promise/package.json new file mode 100644 index 000000000..cb10a2306 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/package.json @@ -0,0 +1,24 @@ +{ + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" + }, + "devDependencies": { + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" + }, + "dependencies": { + "react": "^19.1.0", + "react-dom": "^19.1.0", + "use-debounce": "^10.0.5" + } +} diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/src/app.tsx b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/app.tsx new file mode 100644 index 000000000..69c1d3337 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/app.tsx @@ -0,0 +1,6 @@ +import React from "react"; +import { MyParentComponent } from "./parent"; + +export const App = () => { + return ; +}; diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/src/demo.tsx b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/demo.tsx new file mode 100644 index 000000000..de7b9d074 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/demo.tsx @@ -0,0 +1,20 @@ +import React, { use } from "react"; +import { User } from "./parent"; + +interface MyComponentProps { + userPromise: Promise; +} + +export const MyComponent: React.FC = ({ userPromise }) => { + const userCollection = use(userPromise); + + return ( +
      +
        + {userCollection.map((user, index) => ( +
      • {user.name}
      • + ))} +
      +
      + ); +}; diff --git a/04-frameworks/01-react/02-base/05-list-refactor/src/index.tsx b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/index.tsx similarity index 100% rename from 04-frameworks/01-react/02-base/05-list-refactor/src/index.tsx rename to 04-frameworks/01-react/03-react-hooks/18-use-promise/src/index.tsx diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/src/parent.tsx b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/parent.tsx new file mode 100644 index 000000000..24c7bb748 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/parent.tsx @@ -0,0 +1,34 @@ +import React, { Suspense } from "react"; +import { useDebounce } from "use-debounce"; +import { MyComponent } from "./demo"; + +export interface User { + id: number; + name: string; +} + +const fetchUsers = async (filter): Promise => { + const res = await fetch( + `https://jsonplaceholder.typicode.com/users?name_like=${filter}` + ); + return res.json(); +}; + +export const MyParentComponent = () => { + const [filter, setFilter] = React.useState(""); + const [debouncedFilter] = useDebounce(filter, 1500); + + const usersPromise = React.useMemo( + () => fetchUsers(debouncedFilter), + [debouncedFilter] + ); + + return ( + <> + setFilter(e.target.value)} /> + Loading}> + + + + ); +}; diff --git a/04-frameworks/01-react/03-react-hooks/00-boilerplate/src/styles.css b/04-frameworks/01-react/03-react-hooks/18-use-promise/src/styles.css similarity index 100% rename from 04-frameworks/01-react/03-react-hooks/00-boilerplate/src/styles.css rename to 04-frameworks/01-react/03-react-hooks/18-use-promise/src/styles.css diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/tsconfig.json b/04-frameworks/01-react/03-react-hooks/18-use-promise/tsconfig.json new file mode 100644 index 000000000..a057cea1d --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, + "noImplicitAny": false, + "noImplicitReturns": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true + }, + "include": ["src"] +} diff --git a/04-frameworks/01-react/03-react-hooks/18-use-promise/vite.config.ts b/04-frameworks/01-react/03-react-hooks/18-use-promise/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/18-use-promise/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/.babelrc b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme.md b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme.md index aa2a6c825..f607e3e7e 100644 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme.md +++ b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme.md @@ -1,6 +1,6 @@ # 15 Promise unmounted -## Resume +## Summary This example takes as a starting point the example _14-use-ref-dom_. @@ -63,7 +63,7 @@ export const MyChildComponent = () => { - Now we want to launch an ajax request every time the user writes in the filter's text field (we'll add some latency). -_./src/demo.js_ +_./src/demo.tsx_ ```diff export const MyChildComponent = () => { diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme_es.md b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme_es.md index d755c4003..5e0597848 100644 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme_es.md +++ b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/Readme_es.md @@ -28,7 +28,7 @@ npm install Primero creamos el armazon -_./src/demo.js_ +_./src/demo.tsx_ ```tsx import React from "react"; @@ -65,7 +65,7 @@ export const MyChildComponent = () => { - Ahora queremos lanzar una petición ajax cada vez que el usuario escriba en el campo de texto del filtro (añadiremos algo de latencia). -_./src/demo.js_ +_./src/demo.tsx_ ```diff export const MyChildComponent = () => { diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/index.html b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/index.html new file mode 100644 index 000000000..fe100be04 --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/index.html @@ -0,0 +1,13 @@ + + + + + + React App - React hooks + + + +
      + + + diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/package.json b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/package.json index d434b896c..9ee970f00 100644 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/package.json +++ b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/package.json @@ -1,40 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "use-debounce": "^8.0.1" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/src/index.html b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
      - - diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/tsconfig.json b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/tsconfig.json +++ b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/vite.config.ts b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/webpack.config.js b/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/03-react-hooks/99-promise-unmounted-R17/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/.babelrc b/04-frameworks/01-react/04-basic-app/00-boiler-plate/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/index.html b/04-frameworks/01-react/04-basic-app/00-boiler-plate/index.html new file mode 100644 index 000000000..050566921 --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/index.html @@ -0,0 +1,13 @@ + + + + + + React App + + + +
      + + + diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/package.json b/04-frameworks/01-react/04-basic-app/00-boiler-plate/package.json index 50e9c4ccc..9ee970f00 100644 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/package.json +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/package.json @@ -1,39 +1,23 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0" + "react": "^19.1.0", + "react-dom": "^19.1.0" } } diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme.md b/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme.md index 1afae0061..6c71760df 100644 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme.md +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme.md @@ -1,125 +1,17 @@ -# 03 Webpack React +# Boiler plate Vite React -## Summary +## Resumen -This example takes the _02-webpack-boiler_ example as a starting point. +We take the boiler plate from _./04-frameworks//01-react/02-base/02-vite-react_ -We will go step by step adding the necessary configuration so that we integrate -**React** into our build process. - -# Step by Step guide - -- First we copy the previous example, and do a _npm install_ - -```bash -npm install -``` - -- Let's install _react_ and _react-dom_ +- Check we left everything working: ```bash -npm install react react-dom --save +npm i ``` -- Let's install _react_ and _react-dom_ typings - -```bash -npm install @types/react @types/react-dom --save-dev -``` - -This way we have the React library and the bindings to integrate with a web browser. - -- In the index.html we are going to put the _div_ that will serve as entry point to instantiate our React application. our React application. - -_./src/index.html_ - -```diff - --

      Hello World !

      -+
      - -``` - -- Let's create our first React component. - -_./src/app.tsx_ - -```tsx -import React from "react"; - -export const App = () => { - return

      Hello React !!

      ; -}; -``` - -- It's time to instantiate that main component, to be able to integrate it with the browser we have to make use of _ReactDOM.render_. - -_./src/index.tsx_ - -```tsx -import React from "react"; -import ReactDOM from "react-dom"; -import { App } from "./app"; - -ReactDOM.render( -
      - -
      , - document.getElementById("root") -); -``` - -- We are on the right track, but if we try to run this it will fail, since _babel_ does not know how to transform the _jsx_ (remember that this was a sugar, which was actually an XML) into javaScript, in order for babel to be able to understand this we have to install the _preset_ _@babel/preset-react_ - -First we install it and the configure it. - -```bash -npm install @babel/preset-react --save-dev -``` - -_.babelrc_ - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", -+ "@babel/preset-react" - ] -} -``` - -> By the way the _rc_ suffix is pretty usual in linux it's stands for "runcom" -> (CTSS system 1962-63) Script file containing startup instructions for an application program. -> In other words, "rc" is just something that stuck from back in the sixties, and has been used quite often for configuration files in different sorts of programs since, including Node, Babel and many, many others. -> More info [on stackoverflow](https://stackoverflow.com/questions/36212256/what-are-rc-files-in-nodejs). - -> Another curiosity... what is a _preset_ ... let's start with what is a babel plugin: babel transformations are -> enabled by applying plugins, there are plenty of plugins and if you have to go adding one by one it can become a nightmare, -> in order to make this easier, babel has grouped common sets of plugins in _presets_, for instance @babel-preset-react -> includes the following plugins: - -- @babel/plugin-syntax-jsx -- @babel/plugin-transform-react-jsx -- @babel/plugin-transform-react-display-name - -- Is time to double check the _webpack.config.js_ - -- We can make sure that we have _ts_ and _tsx_ as valid extensions. -- Also that in the loader we accept both _ts_ and _tsx_. -- And in the app we have as entry point _index.tsx_. - -* Let's check that things are working as expected: +y ```bash npm start ``` - - - - - - - - - diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme_es.md b/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme_es.md index bb34f2812..937b4cf12 100644 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme_es.md +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/readme_es.md @@ -1,118 +1,16 @@ -# 03 Webpack React +# Boiler plate Vite React ## Resumen -Este ejemplo toma como punto de partida el ejemplo _02-webpack-boiler_. +Tomamos el boiler plate de _./04-frameworks//01-react/02-base/02-vite-react_ -Vamos a ir paso a paso añdiendo la configuración necesaria para que integrar -**React** en nuestro proceso de build. - -## Paso a Paso - -- Primero copiamos el ejemplo anterior, y hacemos un _npm install_ - -```bash -npm install -``` - -- Vamos a instalar _react_ y _react-dom_ - -```bash -npm install react react-dom --save -``` - -- Vamos a instalarnos los typing de _react_ y _react-dom_ +- Vamos a comprobar que hemos dejado todo funcionando: ```bash -npm install @types/react @types/react-dom --save-dev -``` - -Así tenemos la librería de React y los bindings para que se integre con un navegador web. - -- En el index.html vamos a meter el _div_ que nos servirá como punto de entrada para instanciar - nuestra aplicación React. - -_./src/index.html_ - -```diff - --

      Hello World !

      -+
      - -``` - -- Vamos a crear nuestro primero componente React. - -_./src/app.tsx_ - -```tsx -import React from "react"; - -export const App = () => { - return

      Hello React !!

      ; -}; +npm i ``` -- Es hora de instanciar ese compente principal, para poder integrarlo con el navegador - tenemos que hacer uso a _ReactDOM.render_ - -_./src/index.tsx_ - -```tsx -import React from "react"; -import { createRoot } from "react-dom/client"; -import { App } from "./app"; - -const container = document.getElementById("root"); -const root = createRoot(container); - -root.render(); -``` - -- Vamos por buen camino, pero si intentamos ejecutar esto no va fallar, ya que _babel_ no sabe - como transformar el _jsx_ (recordemos que esto era un azúcar, que en realidad era un XML) a - javaScript, para que babel sea capaz de entender esto tenemos que instalar el _preset_ - _@babel/preset-react_ - -Primero lo instalamos - -```bash -npm install @babel/preset-react --save-dev -``` - -_.babelrc_ - -```diff -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", -+ "@babel/preset-react" - ] -} -``` - -> Por cierto, el sufijo _rc_ es bastante habitual en linux, significa "runcom". -> (Sistema CTSS 1962-63) Archivo de script que contiene instrucciones de inicio para un programa de aplicación. -> En otras palabras, "rc" es algo que se quedó atrás en los años sesenta, y se ha utilizado con bastante frecuencia para los archivos de configuración en diferentes tipos de programas desde entonces, incluyendo Node, Babel y muchos, muchos otros. -> Más información [en stackoverflow](https://stackoverflow.com/questions/36212256/what-are-rc-files-in-nodejs). - -> Otra curiosidad... qué es un _preset_ ... empecemos por lo que es un plugin de babel: las transformaciones de babel -> se habilitan aplicando plugins, hay un montón de plugins y si tienes que ir añadiendo uno a uno se puede convertir en una pesadilla, -> para hacer esto más fácil, babel ha agrupado conjuntos comunes de plugins en _presets_, por ejemplo @babel-preset-react -> incluye los siguientes plugins: - -- @babel/plugin-syntax-jsx -- @babel/plugin-transform-react-jsx -- @babel/plugin-transform-react-display-name - -- Es hora de saltar al _webpack.config.js_ - -- Nos podemos asegurar de que tenemos como extension valida _ts_ y _tsx_ -- También que en el loader aceptamos tanto _ts_ como _tsx_ -- Y en el app tenemos como punto de entrada _index.tsx_ - -* Vamos a comprobar que hemos dejado todo funcionando: +y ```bash npm start diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.html b/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
      - - diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.tsx b/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.tsx index 7e439b87e..1b533b96d 100644 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.tsx +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/src/index.tsx @@ -1,8 +1,9 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; -const container = document.getElementById("root"); -const root = createRoot(container); +const rootElement = document.getElementById("root"); +const root = createRoot(rootElement); root.render(); diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/tsconfig.json b/04-frameworks/01-react/04-basic-app/00-boiler-plate/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/tsconfig.json +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/vite.config.ts b/04-frameworks/01-react/04-basic-app/00-boiler-plate/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/00-boiler-plate/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/04-basic-app/00-boiler-plate/webpack.config.js b/04-frameworks/01-react/04-basic-app/00-boiler-plate/webpack.config.js deleted file mode 100644 index 326060f82..000000000 --- a/04-frameworks/01-react/04-basic-app/00-boiler-plate/webpack.config.js +++ /dev/null @@ -1,54 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/04-basic-app/01-routing/.babelrc b/04-frameworks/01-react/04-basic-app/01-routing/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/04-basic-app/01-routing/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/04-basic-app/01-routing/index.html b/04-frameworks/01-react/04-basic-app/01-routing/index.html new file mode 100644 index 000000000..050566921 --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/01-routing/index.html @@ -0,0 +1,13 @@ + + + + + + React App + + + +
      + + + diff --git a/04-frameworks/01-react/04-basic-app/01-routing/package.json b/04-frameworks/01-react/04-basic-app/01-routing/package.json index 880a61213..360ceb19a 100644 --- a/04-frameworks/01-react/04-basic-app/01-routing/package.json +++ b/04-frameworks/01-react/04-basic-app/01-routing/package.json @@ -1,40 +1,24 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "react-router-dom": "^6.3.0" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.8.2" } } diff --git a/04-frameworks/01-react/04-basic-app/01-routing/src/index.html b/04-frameworks/01-react/04-basic-app/01-routing/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/04-basic-app/01-routing/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
      - - diff --git a/04-frameworks/01-react/04-basic-app/01-routing/src/index.tsx b/04-frameworks/01-react/04-basic-app/01-routing/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/04-basic-app/01-routing/src/index.tsx +++ b/04-frameworks/01-react/04-basic-app/01-routing/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/04-basic-app/01-routing/tsconfig.json b/04-frameworks/01-react/04-basic-app/01-routing/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/04-basic-app/01-routing/tsconfig.json +++ b/04-frameworks/01-react/04-basic-app/01-routing/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/04-basic-app/01-routing/vite.config.ts b/04-frameworks/01-react/04-basic-app/01-routing/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/01-routing/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/04-basic-app/01-routing/webpack.config.js b/04-frameworks/01-react/04-basic-app/01-routing/webpack.config.js deleted file mode 100644 index 749d7f25d..000000000 --- a/04-frameworks/01-react/04-basic-app/01-routing/webpack.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - publicPath: "/", - }, - devServer: { - historyApiFallback: true, - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/04-basic-app/02-login/.babelrc b/04-frameworks/01-react/04-basic-app/02-login/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/04-basic-app/02-login/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/04-basic-app/02-login/index.html b/04-frameworks/01-react/04-basic-app/02-login/index.html new file mode 100644 index 000000000..050566921 --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/02-login/index.html @@ -0,0 +1,13 @@ + + + + + + React App + + + +
      + + + diff --git a/04-frameworks/01-react/04-basic-app/02-login/package.json b/04-frameworks/01-react/04-basic-app/02-login/package.json index 880a61213..360ceb19a 100644 --- a/04-frameworks/01-react/04-basic-app/02-login/package.json +++ b/04-frameworks/01-react/04-basic-app/02-login/package.json @@ -1,40 +1,24 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "react-router-dom": "^6.3.0" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.8.2" } } diff --git a/04-frameworks/01-react/04-basic-app/02-login/src/index.html b/04-frameworks/01-react/04-basic-app/02-login/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/04-basic-app/02-login/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
      - - diff --git a/04-frameworks/01-react/04-basic-app/02-login/src/index.tsx b/04-frameworks/01-react/04-basic-app/02-login/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/04-basic-app/02-login/src/index.tsx +++ b/04-frameworks/01-react/04-basic-app/02-login/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/04-basic-app/02-login/tsconfig.json b/04-frameworks/01-react/04-basic-app/02-login/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/04-basic-app/02-login/tsconfig.json +++ b/04-frameworks/01-react/04-basic-app/02-login/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/04-basic-app/02-login/vite.config.ts b/04-frameworks/01-react/04-basic-app/02-login/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/02-login/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/04-basic-app/02-login/webpack.config.js b/04-frameworks/01-react/04-basic-app/02-login/webpack.config.js deleted file mode 100644 index 749d7f25d..000000000 --- a/04-frameworks/01-react/04-basic-app/02-login/webpack.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - publicPath: "/", - }, - devServer: { - historyApiFallback: true, - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/04-basic-app/03-list/.babelrc b/04-frameworks/01-react/04-basic-app/03-list/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/04-basic-app/03-list/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/04-basic-app/03-list/index.html b/04-frameworks/01-react/04-basic-app/03-list/index.html new file mode 100644 index 000000000..050566921 --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/03-list/index.html @@ -0,0 +1,13 @@ + + + + + + React App + + + +
      + + + diff --git a/04-frameworks/01-react/04-basic-app/03-list/package.json b/04-frameworks/01-react/04-basic-app/03-list/package.json index 880a61213..360ceb19a 100644 --- a/04-frameworks/01-react/04-basic-app/03-list/package.json +++ b/04-frameworks/01-react/04-basic-app/03-list/package.json @@ -1,40 +1,24 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "react-router-dom": "^6.3.0" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.8.2" } } diff --git a/04-frameworks/01-react/04-basic-app/03-list/src/index.html b/04-frameworks/01-react/04-basic-app/03-list/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/04-basic-app/03-list/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
      - - diff --git a/04-frameworks/01-react/04-basic-app/03-list/src/index.tsx b/04-frameworks/01-react/04-basic-app/03-list/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/04-basic-app/03-list/src/index.tsx +++ b/04-frameworks/01-react/04-basic-app/03-list/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/04-basic-app/03-list/tsconfig.json b/04-frameworks/01-react/04-basic-app/03-list/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/04-basic-app/03-list/tsconfig.json +++ b/04-frameworks/01-react/04-basic-app/03-list/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/04-basic-app/03-list/vite.config.ts b/04-frameworks/01-react/04-basic-app/03-list/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/03-list/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/04-basic-app/03-list/webpack.config.js b/04-frameworks/01-react/04-basic-app/03-list/webpack.config.js deleted file mode 100644 index 749d7f25d..000000000 --- a/04-frameworks/01-react/04-basic-app/03-list/webpack.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - publicPath: "/", - }, - devServer: { - historyApiFallback: true, - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -}; diff --git a/04-frameworks/01-react/04-basic-app/04-detail/.babelrc b/04-frameworks/01-react/04-basic-app/04-detail/.babelrc deleted file mode 100644 index 469d3d55f..000000000 --- a/04-frameworks/01-react/04-basic-app/04-detail/.babelrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "presets": [ - "@babel/preset-env", - "@babel/preset-typescript", - "@babel/preset-react" - ] -} diff --git a/04-frameworks/01-react/04-basic-app/04-detail/index.html b/04-frameworks/01-react/04-basic-app/04-detail/index.html new file mode 100644 index 000000000..050566921 --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/04-detail/index.html @@ -0,0 +1,13 @@ + + + + + + React App + + + +
      + + + diff --git a/04-frameworks/01-react/04-basic-app/04-detail/package.json b/04-frameworks/01-react/04-basic-app/04-detail/package.json index 880a61213..360ceb19a 100644 --- a/04-frameworks/01-react/04-basic-app/04-detail/package.json +++ b/04-frameworks/01-react/04-basic-app/04-detail/package.json @@ -1,40 +1,24 @@ { - "name": "react-example", - "version": "1.0.0", - "description": "", - "main": "index.js", + "name": "hello-vite", + "private": true, + "version": "0.0.0", + "type": "module", "scripts": { - "start": "run-p -l type-check:watch start:dev", - "type-check": "tsc --noEmit", - "type-check:watch": "npm run type-check -- --watch", - "start:dev": "webpack-dev-server --mode development --open", - "build": "rimraf dist && webpack --mode development" + "start": "vite --host", + "build": "vite build", + "preview": "vite preview" }, - "author": "", - "license": "ISC", "devDependencies": { - "@babel/cli": "^7.17.10", - "@babel/core": "^7.17.10", - "@babel/preset-env": "^7.17.10", - "@babel/preset-react": "^7.17.12", - "@babel/preset-typescript": "^7.16.7", - "@types/react": "^18.0.9", - "@types/react-dom": "^18.0.4", - "babel-loader": "^8.2.5", - "css-loader": "^6.7.1", - "html-loader": "^3.1.0", - "html-webpack-plugin": "^5.5.0", - "npm-run-all": "^4.1.5", - "rimraf": "^3.0.2", - "style-loader": "^3.3.1", - "typescript": "^4.6.4", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2", - "webpack-dev-server": "^4.9.0" + "@types/react": "^19.1.8", + "@types/react-dom": "^19.1.6", + "@vitejs/plugin-react": "^4.6.0", + "typescript": "^5.8.3", + "vite": "^7.0.4", + "vite-plugin-checker": "^0.10.0" }, "dependencies": { - "react": "^18.1.0", - "react-dom": "^18.1.0", - "react-router-dom": "^6.3.0" + "react": "^19.1.0", + "react-dom": "^19.1.0", + "react-router-dom": "^7.8.2" } } diff --git a/04-frameworks/01-react/04-basic-app/04-detail/src/index.html b/04-frameworks/01-react/04-basic-app/04-detail/src/index.html deleted file mode 100644 index a3d74b719..000000000 --- a/04-frameworks/01-react/04-basic-app/04-detail/src/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - My App Example - - -
      - - diff --git a/04-frameworks/01-react/04-basic-app/04-detail/src/index.tsx b/04-frameworks/01-react/04-basic-app/04-detail/src/index.tsx index 7e439b87e..7c541901b 100644 --- a/04-frameworks/01-react/04-basic-app/04-detail/src/index.tsx +++ b/04-frameworks/01-react/04-basic-app/04-detail/src/index.tsx @@ -1,6 +1,7 @@ import React from "react"; import { createRoot } from "react-dom/client"; import { App } from "./app"; +import "./styles.css"; const container = document.getElementById("root"); const root = createRoot(container); diff --git a/04-frameworks/01-react/04-basic-app/04-detail/tsconfig.json b/04-frameworks/01-react/04-basic-app/04-detail/tsconfig.json index 3312b5f1e..a057cea1d 100644 --- a/04-frameworks/01-react/04-basic-app/04-detail/tsconfig.json +++ b/04-frameworks/01-react/04-basic-app/04-detail/tsconfig.json @@ -1,18 +1,19 @@ { "compilerOptions": { - "target": "es6", - "module": "es6", - "moduleResolution": "node", - "declaration": false, + "esModuleInterop": true, + "isolatedModules": true, + "jsx": "react-jsx", + "lib": ["ESNext", "DOM"], + "module": "ESNext", + "moduleResolution": "bundler", + "noEmit": true, "noImplicitAny": false, - "allowSyntheticDefaultImports": true, - "sourceMap": true, - "jsx": "react", - "noLib": false, - "suppressImplicitAnyIndexErrors": true, + "noImplicitReturns": true, + "resolveJsonModule": true, "skipLibCheck": true, - "esModuleInterop": true + "sourceMap": true, + "target": "ESNext", + "useDefineForClassFields": true }, - "include": ["src/**/*"], - "exclude": ["node_modules"] + "include": ["src"] } diff --git a/04-frameworks/01-react/04-basic-app/04-detail/vite.config.ts b/04-frameworks/01-react/04-basic-app/04-detail/vite.config.ts new file mode 100644 index 000000000..a0024d88e --- /dev/null +++ b/04-frameworks/01-react/04-basic-app/04-detail/vite.config.ts @@ -0,0 +1,7 @@ +import { defineConfig } from "vite"; +import checker from "vite-plugin-checker"; +import react from "@vitejs/plugin-react"; + +export default defineConfig({ + plugins: [checker({ typescript: true }), react()], +}); diff --git a/04-frameworks/01-react/04-basic-app/04-detail/webpack.config.js b/04-frameworks/01-react/04-basic-app/04-detail/webpack.config.js deleted file mode 100644 index 749d7f25d..000000000 --- a/04-frameworks/01-react/04-basic-app/04-detail/webpack.config.js +++ /dev/null @@ -1,58 +0,0 @@ -const HtmlWebpackPlugin = require("html-webpack-plugin"); -const path = require("path"); -const basePath = __dirname; - -module.exports = { - context: path.join(basePath, "src"), - resolve: { - extensions: [".js", ".ts", ".tsx"], - }, - entry: { - app: ["./index.tsx", "./styles.css"], - }, - devtool: "eval-source-map", - stats: "errors-only", - output: { - filename: "[name].[chunkhash].js", - publicPath: "/", - }, - devServer: { - historyApiFallback: true, - }, - module: { - rules: [ - { - test: /\.tsx?$/, - exclude: /node_modules/, - loader: "babel-loader", - }, - { - test: /\.(png|jpg)$/, - type: "asset/resource", - }, - { - test: /\.html$/, - loader: "html-loader", - }, - { - test: /\.css$/, - exclude: /node_modules/, - use: [ - { - loader: "style-loader", - }, - { - loader: "css-loader", - }, - ], - }, - ], - }, - plugins: [ - //Generate index.html in /dist => https://github.com/ampedandwired/html-webpack-plugin - new HtmlWebpackPlugin({ - filename: "index.html", //Name of file in ./dist/ - template: "index.html", //Name of template in ./src - }), - ], -};