Kitabı oku: «Ejercicios prácticos con React», sayfa 3
Estilización de componentes con clases CSS y estilos en línea
En la última receta ha aprendido a crear componentes de clase. Ahora va a añadir algunas CSS al componente Home.
En React, una de las mejores prácticas es que el componente y el archivo de estilo compartan el mismo directorio. Si ha trabajado con PHP, Node, o cualquier otro lenguaje de servidor, probablemente escribe los estilos en un archivo style.css, y lo incluye usando la etiqueta link en la plantilla. React utiliza Webpack, el empaquetador de módulos más popular en la actualidad. Con Webpack puede configurar la forma en la que quiere tratar los estilos (utilizando directamente CSS o utilizando un preprocesador CSS como Sass, Stylus, o Less CSS), y con Webpack puede implementar módulos CSS. Esta es una forma eficaz de evitar los tres grandes problemas de CSS:
• Ausencia de conflictos (sobreescritura involuntaria de CSS)
• Dependencias explícitas (estilos por componente)
• No tiene alcance global
En el Capítulo 10, Dominio de Webpack 4.x, se describirá Webpack, y podrá implementar módulos CSS en el proyecto utilizando Sass o Stylus.
Cómo hacerlo...
Ahora va a añadir CSS al componente Home:
1. Creará una nueva aplicación o usará la anterior (my-first-react-app).
2. A continuación creará un nuevo archivo CSS para el componente Home. Va a reutilizar el componente Home que creó en la última receta. Ahora necesita generar un archivo Home.css al mismo nivel que el archivo Home.js (dentro de la carpeta components). Antes de llevar a cabo este archivo, va a hacer pequeñas modificaciones en el componente Home:

3. Ahora añadirá estilos a Home.css. Básicamente, ha envuelto el componente en div con className de Home, y dentro tiene una etiqueta <h1> con el texto Welcome to Codejobs, y luego una etiqueta <p> con un mensaje. Necesita importar el archivo Home.css directamente, y después de esto el archivo CSS se verá de la siguiente manera:


4. Suponga ahora que necesita añadir un estilo en línea. Para ello utilizará la propiedad style, y es necesario escribir las propiedades CSS en camelCase y entre {{ }}, como se hace a continuación:


5. También puede pasar un objeto a la propiedad style, como hace a continuación:

Cómo funciona...
Como puede ver, es sencillo conectar un archivo CSS al componente, y si ha seguido los pasos correctamente, el sitio debería tener el siguiente aspecto:

Hay más...
Seguramente tendrá curiosidad por saber cómo se añade el código CSS al navegador, ya que no ha importado ningún archivo CSS directamente al proyecto (mediante una etiqueta <link>, por ejemplo). Bueno, le sorprenderá ver que el código CSS se ha inyectado en la etiqueta <head> utilizando la etiqueta <style> para cada hoja de estilo importada. Si inspecciona el proyecto con Chrome DevTools verá algo similar a esto:

Este comportamiento se debe a que style-loader es un cargador Webpack que se utiliza por defecto en la aplicación cuando la crea con create-react-app:

Cuando emplea create-react-app no se puede modificar la configuración de Webpack directamente porque utiliza un paquete llamado react-scripts, pero en el Capítulo 10, Dominio de Webpack, verá cómo configurar Webpack cuando no utilice un kit de inicio como create-react-app.
Hay otros cargadores Webpack que tienen distintos cometidos, como css-loader para módulos CSS, sass-loader para implementar Sass, stylus-loader para implementar Stylus, y extract-text-plugin para mover el código CSS al archivo .css en lugar de inyectarlo en el DOM (esto se utiliza generalmente en la fase de producción).
Paso de props a componentes y su validación con PropTypes
Hasta ahora se ha familiarizado con los componentes de React, pero hay más cosas que intervienen en la renderización de HTML estáticas. Como en cualquier aplicación, necesita poder enviar información (vía props) a distintos elementos. En esta receta, va a crear nuevos componentes: Header, Content y Footer (que agrupará en una carpeta llamada layout), enviará algunos props (como atributos y como hijos) y los validará con PropTypes.
Cómo hacerlo...
Va a crear en primer lugar el componente Header utilizando la misma aplicación de React que creó antes.
1. En este momento, la cabecera (header) se encuentra en App.js: import React, { Component } from 'react'; import logo from '../shared/images/logo.svg'; import Home from './Home/Home';

2. Mueva la cabecera al nuevo componente Header y luego lo importa al componente App. Como los componentes del diseño son globales, y por tanto compartidos, necesita crear un directorio de diseño en su directorio de componentes compartidos (src/shared/components/layout).
3. Antes de continuar, debe instalar un paquete llamado prop-types para usar la validación PropTypes:

4. PropTypes se lanzó inicialmente como parte del módulo principal de React y se utiliza en general con componentes de React. PropTypes se usa para documentar o definir los tipos de propiedades que pretende transmitir a los componentes. React comparará los props pasados a los componentes con esas definiciones y, en la fase de desarrollo, enviará una advertencia si no coinciden:

5. La propiedad static de PropTypes es básicamente un objeto en el que necesita definir el tipo de prop que pasará. array, bool, func, number, object, string, y symbol son tipos primitivos, pero hay también tipos particulares, como node, element, instanceOf, oneOf, oneOfType, arrayOf, objectOf, shape y any. Hay una propiedad opcional llamada isRequired que se puede añadir a cualquier tipo de prop si este es obligatorio, y React presentará una advertencia si no está definido.
6. Importe y renderice el componente Header:

No se confunda con el componente <Header/>; no es lo mismo que la etiqueta <header> de HTML5, por eso en React se recomienda usar mayúsculas en los nombres de clases.
7. Todas las propiedades pasadas a los componentes están contenidas en estos props. Seguramente habrá observado que envía solamente el prop title porque es el único que se requiere. El prop url es opcional y también tiene un valor por defecto en la desestructuración (http://localhost:3000). Si no pasa el prop title (título), incluso si tiene el valor por defecto Welcome to React en la desestructuración, se presentará una advertencia como esta:

8. Creación del componente Footer:

9. Hasta ahora, solo ha pasado props como atributos (con componentes de cierre automático <Component />), pero hay otra forma de pasar props como hijos (<Component>Children Content</Component>). Va a crear el componente Content y envíará el componente Home como hijo de Content (Contenido):

10. Con estos cambios, el archivo App.js debería verse de la siguiente forma:

Cómo funciona...
Las validaciones PropTypes son muy importantes para los desarrolladores porque obligan a definir qué tipo de prop va a recibir en los componentes y validan si algunos de ellos son necesarios o no.
Si ha seguido los pasos correctamente, debería ver algo similar a:

Hay más...
Como puede comprobar, hay muchas formas de enviar props a los componentes. Hay más formas de recibir props, como la que usa Redux (a través de un contenedor) o React Router, pero estos son temas que se van a tratar en los siguientes capítulos.
Uso del estado local en componentes
El estado local es una característica fundamental de React para crear componentes dinámicos. Este solo está disponible en componentes de clase, y cada componente gestiona su estado. Puede definir el valor del estado inicial en el constructor del componente, y cuando actualice su valor, el componente se renderizará de nuevo.
El estado local es útil para alternar, para tratar formularios, y se utiliza para gestionar información dentro del mismo componente. No se recomienda usarlo si precisa compartir datos entre diferentes componentes. En ese escenario, necesita implementar el estado Redux, que se tratará en el Capítulo 5, Dominio de Redux.
Cómo hacerlo...
Va a definir el estado inicial. Vea cómo funciona el método de renderizado de un componente cuando se actualiza el estado local:
1. Usará el componente Home, al que va a añadir un constructor y a definir el estado inicial:

2. En este ejemplo definirá el estado local en el constructor como un objeto, y en el renderizado va a imprimir los valores directamente. Utilizará super() al principio del constructor. Este se usa para recurrir al constructor padre (React.Component). Si no lo incluye, se producirá un error como el siguiente:

3. Después de añadir super(), necesita definir el estado inicial como un objeto estándar:

4. Actualización del estado local con this.setState(). Tal como está ahora, el estado no se actualiza. Esto significa que el componente no se renderizará de nuevo. Para actualizar el estado, necesita utilizar el método this.setState() y pasar el nuevo valor del estado. Puede añadir un setTimeout para actualizar el estado de name (nombre) después de 1 segundo (1000 milisegundos), por lo que necesita modificar el método render como se indica a continuación:


5. Si lo ejecuta en un navegador, verá que el primer valor del estado es Carlos, y 1 segundo después este cambiará a Cristina. He añadido console.log para registrar el valor del estado de Name (nombre). Si abre la consola del navegador, verá lo siguiente:

6. Actualización del estado local en el método de ciclo de vida componentDidMount. Posiblemente se preguntará por qué se repite tantas veces. Es muy sencillo, así es como funciona React. Cada vez que se actualiza un estado se dispara el método de renderizado, y en este código añade un setTimeout que actualiza el estado después de un segundo. Esto supone que al método de renderizado se recurre cada segundo, causando un bucle sin fin. Esto afectará al rendimiento de la aplicación, y por eso es necesario tener cuidado al actualizar el estado. Como puede ver, actualizarlo en el método de renderizado no es una buena idea. Entonces ¿dónde debería actualizar el estado? Bueno, depende de la aplicación, pero, por ahora, verá un método que es parte del ciclo de vida de React llamado componentDidMount():

7. Si ejecuta este código y hace uso de la consola, verá lo siguiente:

Cómo funciona...
Con componentDidMount, evita el bucle sin fin. La razón por la que esta aproximación es más adecuada se debe a que componentDidMount se ejecuta una sola vez cuando el componente ya se ha montado, y, en ese método, ejecuta el setTimeout y se actualiza el estado del nombre una sola vez. En las siguientes recetas seguirá aprendiendo sobre los métodos de ciclo de vida de React.
Hay más...
El estado local se utiliza también para gestionar formularios, pero no se describirán los formularios hasta el Capítulo 6, Creación de formularios con Redux Form.
Creación de componentes funcionales o apátridas
Hasta ahora, ha aprendido a crear en React solamente componentes de clase. Estos componentes son útiles cuando se necesita gestionar el estado local, pero, en algunos casos, necesitará renderizar marcado estático. Para componentes estáticos, tendrá que usar componentes funcionales, también conocidos como componentes apátridas. Con ellos mejorará el rendimiento de la aplicación.
En la receta Paso de props a componentes y validación con PropTypes, creará algunos componentes de diseño (Header, Content y Footer). Estos componentes, como puede imaginar, son frecuentemente estáticos (a menos que quiera tener un menú toggle (de presentación / ocultación o alguna información de usuario en la cabecera), así que, en este caso, puede convertirlos en componentes funcionales.
Cómo hacerlo...
Ahora es el momento de convertir el componentes Header en un componente funcional:
1. En primer lugar, vea a qué se parece el actual componente Header:

2. Lo primero que hay que hacer es convertir el componente de clase en una función flecha, y con este cambio, ya no necesita importar React.Component. La segunda parte de la migración es pasar los props como parámetros de la función, en lugar de obtenerlos de this.props, y el último paso es mover el estático propTypes a nodo de la función. Después de estos cambios, el código será el siguiente:


Un componente funcional es equivalente a tener solo el método de renderizado. Por eso solo tiene que devolver directament el JSX.
3. Después de migrar el componente Header, migrará el componente Footer; esto es más fácil porque no tiene props. En primer lugar, vea a qué se parece el componente Footer:


4. Ahora, como componente funcional, debería parecerse a esto:

En este caso, como puede ver, necesita crear una función flecha sin parámetros (porque no tiene props) y devolver directamente el JSX que necesita renderizar.
5. Convierta el componente Content en un componente funcional:


6. Este componente es similar al componente Header. Necesita pasar los props como parámetros y mantener propTypes:

Cómo funciona...
Incluso en componentes funcionales, puede validar PropTypes. Recuerde que, si no necesita datos dinámicos ni estado local, entonces debería considerar utilizar componentes apátridas. Esto mejorará el rendimiento de la aplicación.
Hay más...
Un componente funcional no solo no tiene estado, sino que tampoco tiene los métodos de ciclo de vida de React.
Asimilación de los métodos de ciclo de vida de React
React proporciona métodos para tratar los datos durante el ciclo de vida de un componente. Esta posibilidad es muy útil cuando necesita actualizar la aplicación en determinados momentos.
Cómo hacerlo...
En esta sección se explicará cada ejemplo de forma independiente.
Lista de tareas, implementación de ComponentWillMount
En esta receta, aprenderá los métodos de ciclo de vida en React. Verá cómo fluye la información a través de los métodos, desde que el componente está premontado, pasando por cuando está montado, hasta que está desmontado. La lista de tareas (Todo List) que desarrollará en esta receta se verá de la siguiente manera:

1. Para esta lista de tareas necesita crear una nueva carpeta llamada Todo en el directorio components, y necesita crear los archivos Todo.js y Todo.css. Este es el esqueleto del componente Todo:

2. El constructor. El constructor es un método único que se ejecuta antes de que se inicialice el objeto. El constructor puede usar la palabra clave super para recurrir al constructor de la superclase (clase padre). Este método se utiliza para inicializar el estado local o para unir métodos. Para la lista de tareas, necesita inicializar el estado local en el constructor con algunos valores de las tasks (tareas) y de los ítems (elementos) de la matriz:

3. El método componentWillMount se ejecuta una sola vez antes de montar el componente. En este caso, antes de montarlo, necesita actualizar el estado de los items con las tareas por defecto:

4. Utilizará uuidv4 para generar ID aleatorios. Para instalar este paquete, necesita ejecutar el siguiente comando:

5. Y luego tiene que importarlo, del siguiente modo:

6. Después de haber definido las tareas por defecto, vea cómo hay que renderizar la lista de tareas:


7. JSX se divide en dos partes. La primera es un formulario con una entrada que está conectada al estado local (this.state.task), y guardará la tarea cuando el usuario envíe el formulario (onSubmit). La segunda parte es la lista de componentes en la que va a mostrar la lista de tareas, pasando la matriz de elementos y las funciones markAsCompleted (para marcar una tarea como completada) y removeTask (para eliminar una tarea de la lista).
8. El método handleOnChange se utiliza para conectar el valor de la entrada con el estado de la tarea:

9. El método handleOnSubmit es para actualizar el estado de items y enviar la nueva tarea a la matriz:


10. La función markAsCompleted va a ser requerida por el componente List y necesita recibir el id de la tarea que quiere marcar como completada. Con este, puede encontrar la tarea específica en la matriz ítems, modificar el nodo como completado, y después actualizar el estado local:

11. La función removeTask también se requerirá desde el componente List y, como markAsCompleted, necesita recibir el id para eliminar la tarea específica:

12. Va a unir todas las piezas. El componente Todo debería parecerse a:



13. Ahora que ha completado el componente Todo, vea el aspecto del componente List:


14. Cada vez que utilice una función .map para renderizar los múltiples elementos de React de una matriz, debe añadir el prop clave a cada elemento que ha creado. De lo contrario, React mostrará una advertencia como esta:

15. Seguramente habrá notado que también ha incluido algunos iconos de Font Awesome, y para que funcionen necesita añadir la CDN de Font Awesome en el archivo principal index.html:

16. La última parte es la de CSS para la lista de tareas (puede cambiar los estilos si lo prefiere):


17. No olvide importar el componente Todo al componente App. De otra manera, el componente Todo no se renderizará:

18. Si se han seguido todas las instrucciones correctamente se debería ver la lista de tareas así:
• El estado inicial con las tareas por defecto debería verse así:

• Adición de una nueva tarea:

• Escribe el título de la tarea y después presiona Enter:

• Marque una tarea como terminada:

• Elimine una tarea:

Le reto a que guarde las tareas usando localStorage en lugar de definirlas por defecto con componentWillMount.
El temporizador Pomodoro, implementación del constructor y de componentDidMount
Para comprender componentDidMount, va a crear un temporizador Pomodoro (si no sabe lo que es, puede leer el contenido del siguiente enlace: https://en.wikipedia.org/wiki/Pomodoro_Technique).
El temporizador Pomodoro es tal como se muestra:

Creación del temporizador Pomodoro:
1. Lo primero que necesita hacer es crear una nueva carpeta llamada Pomodoro en el directorio components, así como un archivo llamado Timer.js y el archivo CSS Timer.css. Este es el esqueleto del componente de clase que utilizará en este caso:


2. Para el temporizador Pomodoro, necesita inicializar el estado local en el constructor con valores para la hora y para la alerta (cuando el tiempo ha terminado):

3. Al método componentDidMount se recurre una vez que el componente está montado y se ejecuta solamente una vez. En este caso, después de haber montado el componente, necesita actualizar el estado de time (tiempo) con el tiempo por defecto (25 min), y para ello necesita crear un nuevo método llamado setDefaultTime y, a continuación, ejecutarlo en el método componentDidMount:


4. Después de definir el tiempo por defecto para el estado de time (tiempo), vea cómo tiene que renderizar el temporizador Pomodoro. El método render debería ser así:

5. En este caso, JSX es muy sencillo. Obtenemos los valores del estado local (message, type, y time) y presentamos un div para mostrar la alerta cuando el usuario recibe un mensaje de alerta. Tiene otro div para mostrar el temporizador, y aquí pasa el tiempo actual (expresado en segundos) al método displayTimer, que convertirá esos segundos al formato mm:ss. La última parte del diseño son los botones para seleccionar el tiempo del temporizador (empieza funcionando durante 25 minutos, una pausa corta de 5 minutos o una pausa larga de 15 minutos), y seguramente habrá observado que ejecuta diferentes métodos en el evento onClick para cada tipo de temporizador.
6. setTimeForWork, setTimeForShortBreak y setTimeForLongBreak: el propósito de estas tres funciones es actualizar el mensaje de alerta dependiendo del tipo de temporización y luego recurrir a una función estándar llamada setTime, pasando como parámetro el tiempo específico para cada opción. Vea en primer lugar cómo deberían ser estas tres funciones:


7. Como ya ha aprendido en recetas anteriores, cuando especificamos métodos con funciones flecha en la clase, se vinculan automáticamente (tienen acceso al objeto "this"). Eso significa que no tiene que vincularlos al constructor. Ahora creará el método setTime:

8. Como puede ver, ejecuta un nuevo método llamado restartInterval() y se actualiza el estado local con la variable newTime, que pasa como parámetro (puede ser 1500 segundos = 25 minutos, 300 segundos = 5 minutos 900 segundos = 15 minutos). Seguramente ha notado, por el nombre de la función, que va a usar una función setInterval, que se utiliza para recurrir a la función cada X milisegundos. La función restartInterval debería ser así:

9. En este caso, primero borramos el intervalo con clearInterval(this.interval). Esto se debe a que el usuario puede cambiar entre los diferentes tipos de temporización, por lo que necesita borrar el intervalo cada vez que configura un nuevo temporizador. Después de borrar el intervalo, llama a la función countDown cada segundo usando setInterval. La función countDown es como sigue:


10. La última pieza de este rompecabezas es la función displayTimer, que convertirá el tiempo al formato mm:ss y lo presentará en el componente:

11. Va a ponerlo todo junto:




12. Después de haber completado el componente, el último paso es añadir los estilos. Este es el CSS que utiliza el temporizador Pomodoro. Naturalmente, puede cambiarlo si lo prefiere:


No hay que olvidar importar el componente <Timer /> a App.js. Si lo hace todo correctamente, debería ver el temporizador Pomodoro de la siguiente manera:
• En funcionamiento:

• En una pausa breve:

• En una pausa larga:

• Buzzzz, ¡el tiempo ha finalizado!:

Le reto a que añada los botones Play, Pause, and Reset para controlar el temporizador.
Ücretsiz ön izlemeyi tamamladınız.