CursosEmpresasBlogLiveConfPrecios

Reto: loading skeletons

Clase 20 de 23 • Curso de React 17

Contenido del curso

Primeros pasos con React

  • 1
    Cómo aprender React.js

    Cómo aprender React.js

    08:19 min
  • 2
    Cuándo usar React.js

    Cuándo usar React.js

    13:27 min
  • 3
    Cambios en React 18: ReactDOM.createRoot

    Cambios en React 18: ReactDOM.createRoot

    01:21 min
  • 4
    Instalación con Create React App

    Instalación con Create React App

    19:13 min

Fundamentos de React: maquetación

  • 5
    Componentes de TODO Machine

    Componentes de TODO Machine

    20:31 min
  • 6
    JSX: componentes vs. elementos (y props vs. atributos)

    JSX: componentes vs. elementos (y props vs. atributos)

    16:15 min
  • 7
    CSS en React

    CSS en React

    17:54 min

Fundamentos de React: interacción

  • 8
    Manejo de eventos

    Manejo de eventos

    14:40 min
  • 9
    Manejo del estado

    Manejo del estado

    12:50 min
  • 10
    Contando y buscando TODOs

    Contando y buscando TODOs

    21:16 min
  • 11
    Completando y eliminando TODOs

    Completando y eliminando TODOs

    13:34 min

Fundamentos de React: escalabilidad

  • 12
    Organización de archivos y carpetas

    Organización de archivos y carpetas

    16:08 min
  • 13
    Persistencia de datos con Local Storage

    Persistencia de datos con Local Storage

    16:16 min
  • 14
    Custom Hook para Local Storage

    Custom Hook para Local Storage

    12:45 min
  • 15
    Manejo de efectos

    Manejo de efectos

    20:37 min
  • 16
    React Context: estado compartido

    React Context: estado compartido

    16:48 min
  • 17
    useContext

    useContext

    07:10 min

Modales y formularios

  • 18
    Portales: teletransportación de componentes

    Portales: teletransportación de componentes

    15:32 min
  • 19
    Formulario para crear TODOs

    Formulario para crear TODOs

    19:57 min

Retos

  • 20
    Reto: loading skeletons

    Reto: loading skeletons

    Viendo ahora
  • 21
    Reto: icon component

    Reto: icon component

    03:51 min

Próximos pasos

  • 22
    Deploy con GitHub Pages

    Deploy con GitHub Pages

    09:49 min
  • 23
    Toma el Curso de React.js: Patrones de Render y Composición

    Toma el Curso de React.js: Patrones de Render y Composición

    01:37 min
Tomar examen

Escuelas

  • Desarrollo Web
    • Fundamentos del Desarrollo Web Profesional
    • Diseño y Desarrollo Frontend
    • Desarrollo Frontend con JavaScript
    • Desarrollo Frontend con Vue.js
    • Desarrollo Frontend con Angular
    • Desarrollo Frontend con React.js
    • Desarrollo Backend con Node.js
    • Desarrollo Backend con Python
    • Desarrollo Backend con Java
    • Desarrollo Backend con PHP
    • Desarrollo Backend con Ruby
    • Bases de Datos para Web
    • Seguridad Web & API
    • Testing Automatizado y QA para Web
    • Arquitecturas Web Modernas y Escalabilidad
    • DevOps y Cloud para Desarrolladores Web
  • English Academy
    • Inglés Básico A1
    • Inglés Básico A2
    • Inglés Intermedio B1
    • Inglés Intermedio Alto B2
    • Inglés Avanzado C1
    • Inglés para Propósitos Específicos
    • Inglés de Negocios
  • Marketing Digital
    • Fundamentos de Marketing Digital
    • Marketing de Contenidos y Redacción Persuasiva
    • SEO y Posicionamiento Web
    • Social Media Marketing y Community Management
    • Publicidad Digital y Paid Media
    • Analítica Digital y Optimización (CRO)
    • Estrategia de Marketing y Growth
    • Marketing de Marca y Comunicación Estratégica
    • Marketing para E-commerce
    • Marketing B2B
    • Inteligencia Artificial Aplicada al Marketing
    • Automatización del Marketing
    • Marca Personal y Marketing Freelance
    • Ventas y Experiencia del Cliente
    • Creación de Contenido para Redes Sociales
  • Inteligencia Artificial y Data Science
    • Fundamentos de Data Science y AI
    • Análisis y Visualización de Datos
    • Machine Learning y Deep Learning
    • Data Engineer
    • Inteligencia Artificial para la Productividad
    • Desarrollo de Aplicaciones con IA
    • AI Software Engineer
  • Ciberseguridad
    • Fundamentos de Ciberseguridad
    • Hacking Ético y Pentesting (Red Team)
    • Análisis de Malware e Ingeniería Forense
    • Seguridad Defensiva y Cumplimiento (Blue Team)
    • Ciberseguridad Estratégica
  • Liderazgo y Habilidades Blandas
    • Fundamentos de Habilidades Profesionales
    • Liderazgo y Gestión de Equipos
    • Comunicación Avanzada y Oratoria
    • Negociación y Resolución de Conflictos
    • Inteligencia Emocional y Autogestión
    • Productividad y Herramientas Digitales
    • Gestión de Proyectos y Metodologías Ágiles
    • Desarrollo de Carrera y Marca Personal
    • Diversidad, Inclusión y Entorno Laboral Saludable
    • Filosofía y Estrategia para Líderes
  • Diseño de Producto y UX
    • Fundamentos de Diseño UX/UI
    • Investigación de Usuarios (UX Research)
    • Arquitectura de Información y Usabilidad
    • Diseño de Interfaces y Prototipado (UI Design)
    • Sistemas de Diseño y DesignOps
    • Redacción UX (UX Writing)
    • Creatividad e Innovación en Diseño
    • Diseño Accesible e Inclusivo
    • Diseño Asistido por Inteligencia Artificial
    • Gestión de Producto y Liderazgo en Diseño
    • Diseño de Interacciones Emergentes (VUI/VR)
    • Desarrollo Web para Diseñadores
    • Diseño y Prototipado No-Code
  • Contenido Audiovisual
    • Fundamentos de Producción Audiovisual
    • Producción de Video para Plataformas Digitales
    • Producción de Audio y Podcast
    • Fotografía y Diseño Gráfico para Contenido Digital
    • Motion Graphics y Animación
    • Contenido Interactivo y Realidad Aumentada
    • Estrategia, Marketing y Monetización de Contenidos
  • Desarrollo Móvil
    • Fundamentos de Desarrollo Móvil
    • Desarrollo Nativo Android con Kotlin
    • Desarrollo Nativo iOS con Swift
    • Desarrollo Multiplataforma con React Native
    • Desarrollo Multiplataforma con Flutter
    • Arquitectura y Patrones de Diseño Móvil
    • Integración de APIs y Persistencia Móvil
    • Testing y Despliegue en Móvil
    • Diseño UX/UI para Móviles
  • Diseño Gráfico y Arte Digital
    • Fundamentos del Diseño Gráfico y Digital
    • Diseño de Identidad Visual y Branding
    • Ilustración Digital y Arte Conceptual
    • Diseño Editorial y de Empaques
    • Motion Graphics y Animación 3D
    • Diseño Gráfico Asistido por Inteligencia Artificial
    • Creatividad e Innovación en Diseño
  • Programación
    • Fundamentos de Programación e Ingeniería de Software
    • Herramientas de IA para el trabajo
    • Matemáticas para Programación
    • Programación con Python
    • Programación con JavaScript
    • Programación con TypeScript
    • Programación Orientada a Objetos con Java
    • Desarrollo con C# y .NET
    • Programación con PHP
    • Programación con Go y Rust
    • Programación Móvil con Swift y Kotlin
    • Programación con C y C++
    • Administración Básica de Servidores Linux
  • Negocios
    • Fundamentos de Negocios y Emprendimiento
    • Estrategia y Crecimiento Empresarial
    • Finanzas Personales y Corporativas
    • Inversión en Mercados Financieros
    • Ventas, CRM y Experiencia del Cliente
    • Operaciones, Logística y E-commerce
    • Gestión de Proyectos y Metodologías Ágiles
    • Aspectos Legales y Cumplimiento
    • Habilidades Directivas y Crecimiento Profesional
    • Diversidad e Inclusión en el Entorno Laboral
    • Herramientas Digitales y Automatización para Negocios
  • Blockchain y Web3
    • Fundamentos de Blockchain y Web3
    • Desarrollo de Smart Contracts y dApps
    • Finanzas Descentralizadas (DeFi)
    • NFTs y Economía de Creadores
    • Seguridad Blockchain
    • Ecosistemas Blockchain Alternativos (No-EVM)
    • Producto, Marketing y Legal en Web3
  • Recursos Humanos
    • Fundamentos y Cultura Organizacional en RRHH
    • Atracción y Selección de Talento
    • Cultura y Employee Experience
    • Gestión y Desarrollo de Talento
    • Desarrollo y Evaluación de Liderazgo
    • Diversidad, Equidad e Inclusión
    • AI y Automatización en Recursos Humanos
    • Tecnología y Automatización en RRHH
  • Finanzas e Inversiones
    • Fundamentos de Finanzas Personales y Corporativas
    • Análisis y Valoración Financiera
    • Inversión y Mercados de Capitales
    • Finanzas Descentralizadas (DeFi) y Criptoactivos
    • Finanzas y Estrategia para Startups
    • Inteligencia Artificial Aplicada a Finanzas
    • Domina Excel
    • Financial Analyst
    • Conseguir trabajo en Finanzas e Inversiones
  • Startups
    • Fundamentos y Validación de Ideas
    • Estrategia de Negocio y Product-Market Fit
    • Desarrollo de Producto y Operaciones Lean
    • Finanzas, Legal y Fundraising
    • Marketing, Ventas y Growth para Startups
    • Cultura, Talento y Liderazgo
    • Finanzas y Operaciones en Ecommerce
    • Startups Web3 y Blockchain
    • Startups con Impacto Social
    • Expansión y Ecosistema Startup
  • Cloud Computing y DevOps
    • Fundamentos de Cloud y DevOps
    • Administración de Servidores Linux
    • Contenerización y Orquestación
    • Infraestructura como Código (IaC) y CI/CD
    • Amazon Web Services
    • Microsoft Azure
    • Serverless y Observabilidad
    • Certificaciones Cloud (Preparación)
    • Plataforma Cloud GCP

Platzi y comunidad

  • Platzi Business
  • Live Classes
  • Lanzamientos
  • Executive Program
  • Trabaja con nosotros
  • Podcast

Recursos

  • Manual de Marca

Soporte

  • Preguntas Frecuentes
  • Contáctanos

Legal

  • Términos y Condiciones
  • Privacidad
  • Tyc promociones
Reconocimientos
Reconocimientos
Logo reconocimientoTop 40 Mejores EdTech del mundo · 2024
Logo reconocimientoPrimera Startup Latina admitida en YC · 2014
Logo reconocimientoPrimera Startup EdTech · 2018
Logo reconocimientoCEO Ganador Medalla por la Educación T4 & HP · 2024
Logo reconocimientoCEO Mejor Emprendedor del año · 2024
De LATAM conpara el mundo
YoutubeInstagramLinkedInTikTokFacebookX (Twitter)Threads

      Muchas aplicaciones se quedan en blanco mientras cargan su contenido. Otras muestran algún mensaje de "cargando" y luego sí renderizan todo el contenido de la aplicación.

      Pero para ofrecerle una mejor experiencia a nuestros usuarios (UX) es mejor renderizar todo el contenido posible, incluso si no ha terminado de cargar alguna parte de la aplicación. En TODO Machine, por ejemplo, podemos mostrar varios componentes desde el principio aunque no hayamos terminado de cargar la lista de TODOs.

      Pero un párrafo que diga "cargando" definitivamente NO es la mejor forma de comunicarle a los usuarios que estamos cargando (el mensaje es claro, pero podríamos buscar una solución más... estética).

      Existen muchas posibles soluciones, desde animaciones sencillas (como 3 puntitos intercalando diferentes niveles de opacidad) hasta loading skeletons (esqueletos de carga). Incluso existen herramientas interactivas como Create React Content Loader para agilizar estos desarrollos.

      El reto de esta clase es que maquetes cualquiera de estas soluciones y nos la muestres en la sección de comentarios. En esta lectura te mostraré mi solución, pero te recomiendo que no la veas hasta intentar tu propia solución.

      :bulb: Te recomiendo esta lectura: 5 estados clave para crear interfaces coherentes

      Tu propio loading skeleton en React

      Lo primero que vamos a hacer es crear 3 nuevos componentes para trabajarlos independientemente: TodosError, TodosLoading y EmptyTodos.

      carbon.png

      Ya que tenemos estos 3 componentes, ahora vamos a llamarlos desde el componente AppUI para conectarlos con la aplicación.

      carbon (1).png

      ¡Muy bien! Ahora sí podemos concentrarnos mucho mejor para trabajar el estado de carga de TODOS dentro del componente TodosLoading.

      Para empezar, voy a crear y conectar un archivo TodosLoading.css para definir los estilos de mi esqueleto:

      carbon (2).png

      Llegó el momento más importante: maquetar.

      Debemos definir qué elementos necesitamos para el esqueleto y luego les daremos estilos con CSS. Como la idea es replicar la estructura de un TODO, vamos a necesitar una cajita para el contenedor del TODO, una cajita para el ícono de completar, otra cajita para el ícono de borrar y una última cajita para el texto.

      :bulb: Le digo a cada elemento "cajita" porque el objetivo de los esqueletos de carga no es replicar todos estos elementos, sino que cada uno será un elemento "fantasma". Deben ser lo suficientemente parecidos a los TODOs reales para que los usuarios entiendan que estos elementos están relacionados con los TODOs, pero lo suficientemente abstractos y grisáceos para que se entienda que aún los estamos cargando.

      carbon (3).png

      ¡Y ahora debemos crear los estilos!

      Primero vamos a definir los tamaños y posiciones de cada elemento (tal cual copiando y pegando los estilos del TodoItem.css, pero cambiando los nombres de las clases y descartando las propiedades innecesarias):

      carbon (4).png

      Ahora vamos a todas las cajitas (menos la del texto) para darles un color de fondo con gradiente:

      carbon (5).png

      Luego le configuraremos un tamaño de fondo lo suficientemente grande como para que pueda darla vuelta sin dejar espacios vacíos (400% es más que suficiente):

      carbon (6).png

      Y finalmente le daremos una animación que cambie la posición del fondo al principio, a la mitad y al final (te recomiendo darle al menos 3 segundos de duración para que tu animación no se vea atropellada, sino por el contrario con un efecto suave e hipnotizante):

      carbon (7).png

      :bulb: Puedes ir a useLocalStorage.js y cambiar el tiempo que tardamos en llamar a nuestro efecto con la función setTimeout para poder visualizar tu esqueleto de carga correctamente.

      Recuerda que puedes tomar esta trilogía de cursos para aprender muchísimo más sobre transformaciones, transiciones y animaciones con CSS:

      Curso de Transformaciones y Transiciones con CSS Curso de Animaciones con CSS Curso Práctico de Maquetación y Animaciones con CSS

      ¡Te espero en la siguiente clase para un nuevo reto!

      👉 Aquí puedes encontrar el repositorio de este reto: Clase bonus: loading skeleton

      Comentarios

        Obed Paz

        Obed Paz

        student•
        hace 4 años

        Loading and Empty state screens: .

        . Error State Screen: .

        screenshootTodoError.png

          Luis Alejandro Vera Hernandez

          Luis Alejandro Vera Hernandez

          student•
          hace 4 años

          Me gusta mucho! :D

          Cristian David Contreras López

          Cristian David Contreras López

          student•
          hace 4 años

          Bro, wow, te mamaste te quedo genial.

        Juan Sebastián Poveda Florez

        Juan Sebastián Poveda Florez

        student•
        hace 4 años

        Opte por los clásicos punticos de carga

          Mauricio Gonzalez Falcon

          Mauricio Gonzalez Falcon

          student•
          hace 3 años

          Tu diseño de todo menos clásico, Te quedo genial

          Marco Antonio Alducin Garcia

          Marco Antonio Alducin Garcia

          student•
          hace 3 años

          Me gusta mucho tu animacion.

        Cristian David Rojas Carvajal

        Cristian David Rojas Carvajal

        student•
        hace 5 años

        Hola 😀

        Para que nos muestre varios componentes TodosLoading podemos hacer esto

        {loading && new Array(5).fill(1).map((a, i) => <TodosLoading key={i} />)}

        resultado

        Loading.png

          Juan Castro

          Juan Castro

          teacher•
          hace 5 años

          Fino

          Francisco Israel Jimenez Ramirez

          Francisco Israel Jimenez Ramirez

          student•
          hace 5 años

          hola, gracias por el aporte!!, justo me estaba preguntando como colocar varios sin tener que repetir la maquetación hardcodeada por así decirlo haha !

          Sin título.jpg
          asi me quedo! me parece una buena solución !

        Rodrigo Milesi

        Rodrigo Milesi

        student•
        hace 5 años
        {loading && new Array(4).fill().map((item, index)=>( <LoadingTodo key={index} /> ))}
        const LoadingTodo = () => { return ( <li className="TodoItem-loading"> <div className="LoaderBalls"> <span className="LoaderBalls__item"></span> <span className="LoaderBalls__item"></span> <span className="LoaderBalls__item"></span> </div> </li> ) }
        .TodoItem-loading { background-color: #FAFAFA; position: relative; display: flex; justify-content: center; align-items: center; margin-top: 24px; box-shadow: 0px 5px 50px rgba(32, 35, 41, 0.15); color: #333; min-height: 4.5rem; } .LoaderBalls { width: 90px; display: flex; justify-content: space-between; align-items: center; } .LoaderBalls__item { width: 20px; height: 20px; border-radius: 50%; background: #bec3c5; } .LoaderBalls__item:nth-child(2) { animation: opacitychange 1s ease-in-out infinite; } .LoaderBalls__item:nth-child(3) { animation: opacitychange 1s ease-in-out 0.33s infinite; } .LoaderBalls__item:nth-child(1) { animation: opacitychange 1s ease-in-out 0.66s infinite } @keyframes opacitychange { 0%, 100% { opacity: 0; } 60% { opacity: 1; } }
        localhost_3000_(Moto G4) (2).png
          Nazareno Aznar Altamiranda

          Nazareno Aznar Altamiranda

          student•
          hace 4 años

          Genial la solucion para repetir los todos, no lograba dar con eso ¡Gracias!

        Gustavo Gonzalez Montero

        Gustavo Gonzalez Montero

        student•
        hace 4 años

        Loading state:

        Loading-State.png

        Ideal state:

        Ideal-State.png

        Error state

        Error-State.png

        Empty state:

        Empty-State.png

        All completed state:

        AllCompleted-State.png

        TodoForm

        Todo-Form.png

        Loading code:

        //TodoLoading.js import React from "react" import ContentLoader from "react-content-loader" import './TodoLoad.css' const TodoLoad = (props) => ( <ContentLoader speed={2} width={280} height={40} viewBox="0 0 280 40" backgroundColor="#3d087b" foregroundColor="#f43bea" {...props} > <rect x="48" y="8" rx="3" ry="3" width="88" height="6" /> <rect x="48" y="26" rx="3" ry="3" width="52" height="6" /> <circle cx="20" cy="20" r="20" /> </ContentLoader> ) export { TodoLoad } //AppUI.js: ... {loading && ( <> <TodoLoad/> <TodoLoad/> <TodoLoad/> </> )}

        Error code:

        //TodoError.js import React from "react"; import './TodoError.css' const TodoError = () => { return ( <div className="TodoError"> <i className="fa fa-grav" aria-hidden="true"></i> <p>Vaya, parece que encontramos un problema, danos un poco de tiempo y vuelve a intenar en unos par de minutos...</p> </div> ) } export { TodoError } AppUI.js ... {error && ( <Modal> <TodoError /> </Modal> )}

        Empty code:

        //EmptyTodos.js import React from "react"; import './EmptyTodos.css' const EmptyTodos = () => { return ( <div className="EmptyTodos"> <div className="EmptyTodos-icons"> <i className="fa fa-sun-o" aria-hidden="true"></i> <i className="fa fa-smile-o" aria-hidden="true"></i> </div> <p>¡Crea tu primer TODO!</p> </div> ) } export { EmptyTodos } //AppUI.js ... {(!loading && !searchedTodos.length) && ( <EmptyTodos /> )}

        All completed state:

        //AllCompleted.js import React from 'react' import './AllCompleted.css' const AllCompleted = () => { return ( <div className="AllCompleted"> <i className="fa fa-coffee" aria-hidden="true"></i> <p>Has completado todos tus TODOs!</p> <p>Es hora de un merecido descanzo</p> </div> ) } export { AllCompleted } //AppUI.js ... {(allCompleted && !!searchedTodos.length) && ( <Modal> <AllCompleted /> </Modal> )}

        La variable AllCompleted es un estado que se actualiza al momento de cargar los todos en el custom hook de useLocalStorage, y también se actualiza cada vez que los todos sufren un cambio. Este es mi custom hook con las mejoras de la variable allCompleted y con el useEffect modificado para que solo se ejecute cuando se carga inicialmente

        //useLocalStorage.js import React from "react"; function useLocalStorage(itemName, initialValue) { const [error, setError] = React.useState(false) const [loading, setLoading] = React.useState(true) const [item, setItem] = React.useState(initialValue) const [allCompleted, setAllCompleted] = React.useState(false) const checkAllCompleted = (todos) => { if (Array.isArray(todos)) { const completedTodos = todos.filter(todo => !!todo.completed).length const totalTodos = todos.length if (totalTodos > 0 && (completedTodos === totalTodos)) { setAllCompleted(true) } else { setAllCompleted(false) } } } React.useEffect(() => { setTimeout(() => { try { const localStorageItem = localStorage.getItem(itemName) let parsedItems; if (!localStorageItem) { localStorage.setItem(itemName, JSON.stringify(initialValue)) parsedItems = initialValue } else { parsedItems = JSON.parse(localStorageItem) } setItem(parsedItems) checkAllCompleted(parsedItems) setLoading(false) } catch (error) { setError(error) } }, 1500); },[initialValue, itemName]) const saveItem = (newItem) => { try { localStorage.setItem(itemName, JSON.stringify(newItem)) setItem(newItem) checkAllCompleted(newItem) } catch (error) { setError(error) } } return { item, saveItem, loading, error, allCompleted } } export { useLocalStorage }

        Otras mejoras que hice fueron la implementación del hook useRef para que cuando la app cargue el foco esté en el input de búsqueda. Lo mismo cuando se carga el componente de TodoForm para que se ubique automáticamente en el textarea

        TodoSearch

        //TodoSearch/index.js ... const refInput = React.useRef() React.useEffect(() => { refInput.current.focus() },[]) return ( <section className="TodoSearch"> <input ref={refInput} value={searchValue} onChange={onSearchValueChange} placeholder="Cebolla" /> <i className="fa fa-search" aria-hidden="true"></i> </section> ) ...

        TodoForm

        En TodoForm también puse una validación para un máximo de 40 caracteres por Todo

        const textareaRef = React.useRef() React.useEffect(() => { textareaRef.current.focus() }, []) const onChange = (event) => { setNewTodoValue((prevState) => { let eventValue = '' if (event.target.value.length > 40) { eventValue = prevState } else { eventValue = event.target.value } return eventValue }) } const onCancel = () => { setOpenModal(false) } const onSubmit = (event) => { event.preventDefault() addTodo(newTodoValue) setOpenModal(false) } return ( <form className="TodoForm" onSubmit={onSubmit} > <label>Escribe tu nuevo <span>TODO</span></label> <textarea ref={textareaRef} value={newTodoValue} onChange={onChange} placeholder="Cortar la cebolla para el almuerzo" /> <p>{newTodoValue.length}/40</p> ... </form> ) ...

        Transparent Scroll

        En el TodoList puse una validación para que el alto no supere cierto máximo y así poder hacer scroll sin que el Botón se desplace demasiado y salga del viewport. Y ya que iba a aparecer un scroll le puse estilos para que luzca más estético:

        .TodoList { position: relative; max-height: 450px; margin: 15px 0; padding: 5px 5px; background: var(--background05); border-radius: 10px; overflow-y: scroll; } .TodoList-ul { display: flex; flex-direction: column; width: 280px; } /* * ============================== */ /* * ========== WEBKIT ============ */ /* * ============================== */ ::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, 0.1); border-radius: 25px; } ::-webkit-scrollbar { width: 10px; background: rgba(255, 255, 255, 0.1); border-radius: 25px; } ::-webkit-scrollbar:hover { background: rgba(255, 255, 255, 0.2); box-shadow: 0 0 10px 10px rgba(0, 0, 0, 0.2); } ::-webkit-scrollbar:hover:active { background: rgba(255, 255, 255, 0.25); }
          Gustavo Gonzalez Montero

          Gustavo Gonzalez Montero

          student•
          hace 4 años

          Usé este video para entender como usar el useRef: https://egghead.io/lessons/react-focus-an-input-field-in-react-with-the-useref-and-useeffect-hooks

          En la clase de deploy con GitHub paso el link del repo ;-)

        Angel Choque

        Angel Choque

        student•
        hace 5 años
        loading.png

        yo solo lo puse una animación de carga

          Stiven Trujillo

          Stiven Trujillo

          student•
          hace 4 años

          Uy este esta muy interesante y bonito

          Mauricio Chávez

          Mauricio Chávez

          student•
          hace 4 años

          Que chimba!

        John Orellana

        John Orellana

        student•
        hace 4 años

        Hola devs !! Puede que haya un error en el Modal en el aspecto de sí al momento de agregar todos, nosotros no escribamos la tarea y le demos al botón de agregar , se agrega una tarea vacía, para evitar esto coloque el atributo required en textarea y así no se va una tarea vacía , haciendo que el usuario no ignore llenar este campo!!

          Lean Silva

          Lean Silva

          student•
          hace 3 años

          Podría ser contraproducente, ya que editando el html directamente desde el navegador el usuario podría crear y guardar un "ToDo" vacio y guardarlo en LocalStorage, lo mejor sería hacer las respectivas validaciones con operadores.

        Gustavo A. González G.

        Gustavo A. González G.

        student•
        hace 4 años

        Qué tal?

        localhost_3000__(iPhone 12 Pro) (5).png
        localhost_3000__(iPhone 12 Pro) (6).png
          Juan Castro

          Juan Castro

          teacher•
          hace 4 años

          10/10

          Alejandro Forero Vanegas

          Alejandro Forero Vanegas

          student•
          hace 4 años

          Muy buena la UI!

        Juan Fernando Yepes Muñoz

        Juan Fernando Yepes Muñoz

        student•
        hace 4 años

        Pantalla de carga

        La hice con la herramienta que nos dejaron en la lectura, bastante sencillo hacerlo con esa herramienta la verdad

        loading.png

        Usuario nuevo / o sin TO-DOs

        empty.png

        Por si hay un error ya saben donde ir

        error.png
        Raul Wabe

        Raul Wabe

        student•
        hace 4 años

        Vamos avanzando, está muy bueno el proyecto para llevar varios conceptos

        capturas.png

        Alan Dromundo Arias

        Alan Dromundo Arias

        student•
        hace 3 años

        Aporte en acción:

        . .

        Pantalla de empty todos

        . .

        Pantalla de error todos

        . .

        Pantalla de loading skeletons

        Kevin Andres García Velez

        Kevin Andres García Velez

        student•
        hace 3 años

        Loading State:

        EmptyToDos:

        TheProjectWithTodos:

          Lean Silva

          Lean Silva

          student•
          hace 3 años

          Que elegante! Usaste solo css?

        Luis Felipe Silgado Cortázar

        Luis Felipe Silgado Cortázar

        student•
        hace 5 años

        Usando React Content Loader, aunque debo decir que no me siento cómodo usando medidas absolutas. En un futuro veré cómo hacerlo con medidas relativas.

        import React from 'react' import ContentLoader from 'react-content-loader' export function TodosLoading(props) { return ( <ContentLoader speed={2} width={272} height={102} viewBox="0 0 272 104" backgroundColor="#d9d9d9" foregroundColor="#ecebeb" {...props} > {/* Línea Izquierda */} <rect x="0" y="16" rx="0" ry="0" width="2" height="102" /> {/* Línea derecha */} <rect x="270" y="16" rx="0" ry="0" width="2" height="102" /> {/* Línea superior */} <rect x="0" y="16" rx="0" ry="0" width="272" height="2" /> {/* Línea inferior */} <rect x="0" y="102" rx="0" ry="0" width="272" height="2" /> {/* Check */} <rect x="24" y="48" rx="0" ry="0" width="24" height="24" /> {/* Texto */} <rect x="72" y="28" rx="0" ry="0" width="176" height="24" /> {/* Texto */} <rect x="72" y="68" rx="0" ry="0" width="176" height="24" /> </ContentLoader> ) }
        skeleton.png
        Javier Alejandro Albornoz Pérez

        Javier Alejandro Albornoz Pérez

        student•
        hace 4 años

        Seria bueno usar los React-Icons?

          Juan Castro

          Juan Castro

          teacher•
          hace 4 años

          Yeah, está perfecto :)

        Samuel Montoya Gallo

        Samuel Montoya Gallo

        student•
        hace 3 años

        Aquí mi propuesta de LOADING...

        Screenshot_20230216_083352.png

        Paula Inés Cudicio

        Paula Inés Cudicio

        student•
        hace 3 años

        Tiene una pequeña animación que no supe como cargarla

        localhost_3000_(Surface Duo) (1).png
        localhost_3000_.png
        localhost_3000_(Surface Duo).png
        localhost_3000_(Surface Duo) (3).png
        localhost_3000_(Surface Duo) (2).png
        CHRISTIAN OLIVER SOLANO NUÑEZ

        CHRISTIAN OLIVER SOLANO NUÑEZ

        student•
        hace 4 años

        decidí crear algo mas expresivo EmptyTodos

        starTodo.png

        TodosErrot

        ErrorTodos.png

        TodoLoading

        LoadingTodos.png

          Juan Castro

          Juan Castro

          teacher•
          hace 4 años

          Love it

        Miguel Angel Armenta Acosta

        Miguel Angel Armenta Acosta

        student•
        hace 4 años

        Mi Todo List

        Task3.png
        David Rodriguez

        David Rodriguez

        student•
        hace 4 años
        Captura de Pantalla 2022-01-17 a la(s) 13.06.40.png
        ZANONI ALFREDO SALAS TOBÓN

        ZANONI ALFREDO SALAS TOBÓN

        student•
        hace 4 años

        La verdad no hice muchos cambios al css :C

        introreact.JPG
        introreact2.JPG