Asi es como va actualmente mi TodoMachine
Introducción y requisitos
¿Qué necesitas para aprender React.js?
Maquetación con React.js
¿Qué es un componente?
Componentes de TODO Machine
¿Cómo se comunican los componentes? Props y atributos
Estilos CSS en React
Interacción con React.js
Eventos en React: onClick, onChange
¿Qué es el estado?
Contando TODOs
Buscando TODOs
Completando y eliminando TODOs
Librería de Iconos Personalizados
Iconos en React: librerías y SVG
Iconos con colores dinámicos
Herramientas avanzadas: escalabilidad, organización y persistencia
Local Storage con React.js
Custom Hooks
Organización de archivos y carpetas
Feature-First Directories en React
Tips para naming y abstracción de componentes React
¿Qué son los efectos en React?
Estados de carga y error
Actualizando estados desde useEffect
Reto: loading skeletons
¿Qué es React Context?
useContext
¿Qué son los React Portals?
Reto: estados para abrir y cerrar un modal
Maquetando formularios en React
Crear TODOs: React Context dentro de React Portals
Deploy
Despliegue de TODO Machine en GitHub Pages
Presentación de proyectos para tu portafolio
Próximos pasos: React #UnderTheHood
Diferencias entre versiones de React.js
¿Cuándo realmente necesitas React.js?
Bonus: creando proyectos en React desde cero
React con Create React App
React con Next.js
React con Vite
No tienes acceso a esta clase
¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera
Introducir loading skeletons en nuestra aplicación no solo mejora su aspecto visual durante el proceso de carga de datos, sino que también ofrece a los usuarios una mejor experiencia durante esos momentos de espera. Esta técnica es esencial para evitar las incómodas transiciones con pantallas vacías o mensajes de carga sencillos. Exploraremos cómo implementar estos loading skeletons y darles un toque estético y funcional.
Es crucial empezar asignando componentes específicos para diferentes estados de tu aplicación, como error, carga y vacío. Esto no solo organiza mejor tu código, sino que también te permite personalizar la experiencia del usuario según cada escenario.
En el siguiente ejemplo, se crean directorios y archivos índice para diferentes estados:
// Crear los directorios y archivos de índice
todosLoading/index.js
todosError/index.js
emptyTodos/index.js
La implementación comienza modificando los componentes de carga para que muestren un diseño más atractivo, con la ayuda de CSS y animaciones.
Estructura básica del componente de carga:
Cambiaremos de un simple texto de carga a una estructura de div
y span
que permita aplicar estilos:
function todosLoading() {
return (
<div className="loading-todo-container">
<span className="loading-todo-complete-icon"></span>
<p className="loading-todo-text"></p>
<span className="loading-todo-delete-icon"></span>
</div>
);
}
Incorporación de estilos y animaciones CSS:
Aquí es donde se da vida a los loading skeletons. Utilizamos gradientes y animaciones para crear un efecto dinámico:
.loading-todo-container {
position: relative;
display: flex;
background: linear-gradient(to right, #ddd, #eee, #ddd);
animation: loading 1.5s infinite;
}
@keyframes loading {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
Replicar la estructura del componente original de los items (como los íconos de completar y eliminar) en tu diseño de carga, garantiza que la interfaz visual provisional sea coherente con el diseño final. Así construí nuevas clases que emulan estas posiciones y estilos, asegurando homogeneidad entre el estado de carga y el resultado final, usando un border-radius
y una paleta de colores adecuada.
En este caso, se agregaron varios componentes de carga a la vista inicial, mostrando múltiples loading skeletons al mismo tiempo. Esta decisión estética crea una anticipación visual sobre el contenido que está por venir:
// En AppUI.js
return (
<>
<todosLoading />
<todosLoading />
<todosLoading />
</>
);
Los loading skeletons no solo son agradables a la vista, sino que también ofrecen a los usuarios una experiencia más fluida y menos frustrante al interactuar con una aplicación que está cargando datos. Este enfoque evita dejar a los usuarios con la percepción de error o vacíos inexplicables.
Intenta implementar loading skeletons para otras partes de la aplicación, como el campo de búsqueda de Todo y el conteo de Todo, para asegurar una experiencia cohesiva durante todo el proceso de carga. Esto puede solucionar inconsistencias, como mostrar "0 de 0 todos completados", mejorando aún más la experiencia general.
Finalmente, recuerda que estas prácticas no solo mejoran la apariencia de tu aplicación, sino que también su usabilidad y percepción de profesionalismo. ¡Explora, experimenta y sigue aprendiendo para hacer tus aplicaciones más increíbles!
Aportes 67
Preguntas 4
Asi es como va actualmente mi TodoMachine
Aun no he visto los cursos de animaciones pero me puse a buscar mas o menos como funciona cada propiedad que usa el profesor para entender y aplicarlo a mi diseno.
Aplique lo mismo solo que con mis colores y le agregue un borde con un color con muy baja opacidad
Yo añadí una animación de puntitos rebotando
Cumpliendo con el reto, he utilizado material UI para la animación de <TodosLoading/>
(
import CircularProgress from "@mui/material/CircularProgress"
import Box from "@mui/material/Box"
function TodosLoading () {
return (
<Box sx={{ display: 'flex' }}>
<CircularProgress />
</Box>
)
}
export { TodosLoading}
Aqui dejo una animacion sencilla con dots que hice para el reto !!!
🤗
Asi va quedando
Y esta es otra version
No creo que se vea tan aburrido 😅
Para los que ya saben CSS y quieren seguir avanzando con mas conceptos de react, les dejo el CSS de TodosLoading.js y la estructura del componente
COMPONENTE:
import './TodosLoading.css'
function TodosLoading() {
return (
<div className='LoadingTodo-container'>
<span
className='LoadingTodo-completeIcon'>
</span>
<p className='LoadingTodo-text'></p>
<span
className='LoadinTodo-deleteIcon'></span>
</div>
);
};
export { TodosLoading };
CSS:
.LoadingTodo-container {
position: relative;
display: flex;
justify-content: center;
align-items: center;
margin-top: 24px;
box-shadow: 0px 5px 50px rgba(32, 35 41 0.15);
border-radius: 10px;
padding: 12px 0;
}
.LoadingTodo-text {
margin: 24px 0 24px 24px;
Width: calc(100% - 120px);
font-size: 18px;
line-height: 24px;
font-weight: 400;
}
.LoadingTodo-completeIcon,
.LoadinTodo-deleteIcon {
cursor: pointer;
display: flex;
justify-content: center;
align-items: center;
border-radius: 50px;
height: 48px;
width: 48px;
}
.LoadingTodo-completeIcon {
position: absolute;
left: 12px;
}
.LoadinTodo-deleteIcon {
position: absolute;
top: -24px;
right: 0;
}
.LoadingTodo-container,
.LoadingTodo-completeIcon,
.LoadinTodo-deleteIcon {
background: linear-gradient(90deg, rgba(250, 250, 250, 1), rgb(200, 199, 199));
background-size: 400% 400%;
animation: loadingAnimation 3s ease-in-out infinite;
}
@keyframes loadingAnimation {
0% {
background-position: 0% 50%;
}
50% {
background-position: 100% 50%;
}
100% {
background-position: 0% 50%;
}
};
Gracias!!!
Buenas, dejo mi aporte sobre el loading skeleton.
.TodoLoading,
.TodoLoadingCheck,
.TodosLoadingDelete {
background: linear-gradient(90deg, rgb(25, 25, 25), rgb(76, 76, 76));
background-size: 400% 400%;
animation: skeleton-loading 2s ease-in infinite;
}
@keyframes skeleton-loading {
0% {
background-position: 80% 50%;
}
50% {
background-position: 50% 80%;
}
100% {
background-position: 75% 45%;
}
}
css del min 08:40
Vaya que me demore haciendo girar la ruedita
Reutilizando código del curso del **Curso Práctico de Maquetación y Animaciones con CSS **. Les dejo mi proyecto y mi github.
Les comparto mi loading.
TodosLoading.js
import React from 'react';
import './TodosLoading.css';
function TodosLoading() {
return (
<div className="loading-wave-container">
<div className="loading-wave">
<div className="loading-bar"></div>
<div className="loading-bar"></div>
<div className="loading-bar"></div>
<div className="loading-bar"></div>
</div>
</div>
);
}
export { TodosLoading };
TodosLoading.css
.loading-wave-container {
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
margin-top: 50px;
}
.loading-wave {
width: 300px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
.loading-bar {
width: 20px;
height: 10px;
margin: 0 5px;
background-color: #3498db;
border-radius: 5px;
animation: loading-wave-animation 1s ease-in-out infinite;
}
.loading-bar:nth-child(2) {
animation-delay: 0.1s;
}
.loading-bar:nth-child(3) {
animation-delay: 0.2s;
}
.loading-bar:nth-child(4) {
animation-delay: 0.3s;
}
@keyframes loading-wave-animation {
0% {
height: 10px;
}
50% {
height: 50px;
}
100% {
height: 10px;
}
}
Por acá te dejo mi aporte por si tienes dudas de cómo generar la animación con ese efecto brilloso. Te dejo también un enlace para que aprendas a crearlo por tu cuenta:
–
JSX:
import React from 'react';
import './LoadingTodos.scss';
function LoadingTodos() {
return (
<div className="loading-box">
<div className="loading-animation"></div>
</div>
)
}
export { LoadingTodos }
CSS
//Estilos del contenedor de mis todos
.loading-box {
width: 30rem;
height: 4rem;
margin: 1rem 0;
border: none;
background-color: #ccc;
border-radius: 0.7rem;
position: relative;
overflow: hidden;
}
//Estilos del contenedor de animación
.loading-box {
width: 30rem;
height: 4rem;
margin: 1rem 0;
border: transparent;
border-radius: 0.7rem;
background-color: #e2e5e7;
position: relative;
}
.loading-animation {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 0.5),
rgba(255, 255, 255, 0)
);
background-size: 40px 100%;
background-repeat: no-repeat;
background-position: left -40px top 0;
animation: shine 1s ease infinite;
border-radius: 0.7rem;
}
@keyframes shine {
to {
background-position: right -40px top 0;
}
}
Esta es mi implementación, aún no he visto los cursos de CSS avanzado ni de animaciones, no soy buen diseñador, pero esta es mi respuesta al reto:
El primer elemento, es el skeleton, lo dejé para ver lo que se veía, en comparación con la lista de ToDOs, pero serían igual que lo hizo JuanDC tres elementos, y la barra de cargando información se va cargando. Se hizo con CSS:
TodoLoading.js
import React from 'react';
import './TodosLoading.css';
function TodosLoading() {
return (
<>
<li className={`TodoItem-loading cat-0`}>
<p className={`TodoItem-p-loading`}>
<span className="loader-1"></span>
</p>
</li>
</>
);
}
export {TodosLoading};
y TodoLoading.css
.TodoItem-loading{
list-style-type: none;
display: flex;
justify-content: space-between;
align-items: center;
width: 90%;
margin: 10px auto;
padding: 10px;
/* border: 1px solid darkgray; */
box-shadow: 0px 1px 4px 0 LightBlue;
border-radius: 10px;
background: linear-gradient(90deg, rgba(250,250,250,1), rgb(200, 199, 199));
background-size: 400% 400%;
animation: loadingAnimation 3s ease-in-out infinite;
}
@keyframes loadingAnimation {
0% {background-position: 0% 50%;}
50% {background-position: 100% 50%;}
100% {background-position: 0% 50%;}
}
.TodoItem-p-loading {
width: 100%;
text-align: center;
}
.cat-0 {
border-left: 10px solid gray;
}
.loader-1{
color: gray;
display: inline-block;
font-family: Arial, Helvetica, sans-serif;
font-size: 20px;
line-height: 16px;
font-weight: 400;
position: relative;
}
.loader-1:after{
content: 'Cargando tu información... ';
position: relative;
z-index: 5;
vertical-align:super;
}
.loader-1:before{
content: '';
height: 6px;
border: 1px solid;
border-radius: 10px;
width: 100%;
position: absolute;
bottom: 0px;
background: linear-gradient(#FF3D00 100%, transparent 0) no-repeat;
background-size: 0% auto;
animation: 10s lineGrow linear infinite;
}
@keyframes lineGrow {to { background-size: 100% auto}}
Use la fuente Flow circular
Para hacer que el texto se ve con border radius
Si colocas un de total
console.log(total);
en el componente AppUI, verán que se sigue renderizando ese componente de manera infinita.
Alguna idea de como arreglarlo ?
RETO TodoCounter
import React from "react";
import "./TodoCounter.css";
function TodoCounter({ total, completed }) {
let message;
if (total === 0) {
message = "No hay tareas pendientes.";
} else if (total === completed) {
message = "¡Felicidades, has completado todos los TODOs!";
} else {
message = `Has completado ${completed} de ${total} TODOs`;
}
return <h1 className="TodoCounter">{message}</h1>;
}
export { TodoCounter };
RETO.
Componente:
import React from 'react';
import './TodosLoading.css';
function TodosLoading() {
return (
<div className="loadingProcess"></div>
);
}
export { TodosLoading };
CSS:
.loadingProcess {
position: fixed;
top: 20px;
left: 0;
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
.loadingProcess::after {
content: "";
width: 105px;
height: 105px;
border: 15px solid #f3f3f3;
border-top: 15px solid #72A9F2;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
Creo que me falta aun mejorar. No es si deba quitar la palabra loading y poner un grafico de carga mas intuitivo para el usuario.
Logré hacerle un efecto de onda con bing chat
Yo use TailwindCSS con Flowbite. En su libreria de componentes hay unos spinners muy sencillos y chulos.
Me sentí como un niño en una juguetería JAJAJA… fue mucha la curiosidad que me dio al estilizar el loader y probar con los diferentes estilos de CSS, falta por mejorar miles y miles de cosas… No paremos de aprender.
mi solucion al reto
Le pedi a chatGPT, que me hiciera la pagina con taildwind y react, cuando estuviera cargando:
Esta es su respuesta, a mi me gusto
import React from 'react';
const LoadingPage = () => {
return (
<div className="min-h-screen flex items-center justify-center bg-gray-900 text-white">
<div className="animate-pulse">
<div className="w-20 h-20 rounded-full bg-blue-500"></div>
<div className="mt-4 flex justify-center space-x-2">
<div className="w-4 h-4 rounded-full bg-blue-500"></div>
<div className="w-4 h-4 rounded-full bg-blue-500"></div>
<div className="w-4 h-4 rounded-full bg-blue-500"></div>
</div>
</div>
</div>
);
};
export default LoadingPage;
Aqui les dejo mi metodo, quise hacerlo de esta forma para evitar poner tanto codigo en AppUI.jsx y pues creo que a la hora de hacer responsive los diseños o proyectos con mas contenido no aplicar tres si no numero mayor de skeletons (por llamarlos de alguna forma) aunque me fuese gustado aplicar una logica en la que colocando una etiqueta <li> pueda renderizar N canidades de veces para llenar todo los espacios necesarios tal cual lo hace Youtube a la hora de cargar…
Mi solución la hice así:
Estoy utilizando Sass en mi caso porque se me hace mas facil hacer CSS
En este solamente cree un span y lo multiplique en varios al hacer return
import React from "react";
function TodosLoading() {
const TodoLoading = () =>
<span className="todosLoading"></span>
return (
<>
<TodoLoading />
<TodoLoading />
<TodoLoading />
<TodoLoading />
<TodoLoading />
</>
)
}
export { TodosLoading };
En mi caso estoy utilizando Sass y al archivo donde puse el skeleton decidí llamar TodosLoading.scss y esta compuesto de esta manera el cual va a mostrar una bonita animacion de carga que va de arriba y hacia abajo apareciendo y desapareciendo los elementos
@keyframes loading-skeleton {
0%, 100% {
opacity: 100%;
}
50% {
opacity: 0%;
}
}
.todosLoading {
height: 60px;
width: auto;
background: $todoLoading;
border-radius: 10px;
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding: 2px 10px 2px 10px;
filter: drop-shadow(0px 4px 4px rgba(0, 0, 0, 0.25));
animation: loading-skeleton infinite 1.5s;
&:nth-child(2) {
animation-delay: .2s;
}
&:nth-child(3) {
animation-delay: .4s;
}
&:nth-child(4) {
animation-delay: .2s;
}
&:nth-child(5) {
animation-delay: .4s;
}
Yo lo hice de la siguiente manera que me parecio que es mucho mas facil
Codigo para la parte de TodosLoading.js
import React from "react";
import '../styles/TodosLoading.css'
import 'bootstrap/dist/css/bootstrap.min.css';
import {Spinner} from 'reactstrap';
function TodosLoading(){
return(
<div className="container-loading">
<div className="loading">
<Spinner color= "primary" />
</div>
</div>
);
}
export {TodosLoading};
antes de ejecutarlo recuerden que hay que instalar las dependencias que se hace con el siguiente comando
npm i bootstrap reactstrap
código para la parte de css
.container-loading {
height: 100vh;
position: relative;
}
.loading {
margin: 0;
position: absolute;
top: 50%;
left: 50%;
-ms-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
}
hay ya el loading quedaría centralizado y para mi se vería mucho mas chimbita jejej 😎
pda: No agrego imágenes porque no se como carajos ponerlas (Si alguien sabe que me explique por favor 😢)
Yo estoy utilizando MUI, así que implementé el componente Skeleton.
export const TodoLoading = () => {
return (
<Box>
<Skeleton variant='text' width={350} height={40} />
<Skeleton variant='text' width={350} height={40} />
<Skeleton variant='text' width={350} height={40} />
<Skeleton variant='text' width={350} height={40} />
</Box>
)
}
Aqui dejo mi solucion al TodosLoading, he instalado Chakra UI y Framer-Motion para crearlo:
import { Box, Spinner } from '@chakra-ui/react'
function ToDosLoading() {
return (
<Box className='w-16 h-16 mb-12' >
<Spinner
thickness='4px'
speed='0.65s'
color='#000000'
emptyColor='#707070'
height={'100%'}
width={'100%'}
/>
</Box>
)
}
export default ToDosLoading```
De esta forma va mi estado de carga en mi todo App
[](C:\Users\User\Pictures\Screenshots\Captura de pantalla 2023-10-24 084951.png)
import React from 'react';
import { Bars } from 'react-loader-spinner';
import './TodosLoanding.css';
function TodosLoading() {
return (
<div className="loader-container">
<Bars
color="#00BFFF"
height={100}
width={100}
timeout={3000}
/>
<p>Cargando...</p>
</div>
);
}
export { TodosLoading };
.loader-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 50vh;
}
.loader-container p {
margin-top: 0px;
}
¿Quieres ver más aportes, preguntas y respuestas de la comunidad?