Implementazione di schermate di scheletro in reazione
Pubblicato: 2022-03-10Spinner e caricatori sono stati tradizionalmente il modo per dire agli utenti che il caricamento dei contenuti richiederà un po' di tempo. Sebbene questo approccio sia ottimo, sta rapidamente diventando obsoleto nello sviluppo moderno. Gli schermi Skeleton stanno diventando il sostituto perfetto per i caricatori tradizionali perché si concentrano sui progressi piuttosto che sui tempi di attesa, riducendo così la frustrazione dei tempi di caricamento.
In questo articolo, non analizzeremo le basi della sintassi CSS React o JavaScript, quindi non devi essere un esperto in nessuno di questi linguaggi per seguire.
Gli esperti di UI e UX ci insegnano che, mentre gli utenti aspettano che i contenuti vengano caricati su una pagina, dovremmo tenerli coinvolti.
L'idea alla base dell'utilizzo degli spinner per coinvolgere gli utenti prima del caricamento dei contenuti è ottima; tuttavia, il risultato può essere tutt'altro che ideale perché la maggior parte degli utenti si annoierà a fissare uno spinner animato fittizio come se fosse un orologio. Luke Wroblewski elabora questo.
Gli schermi Skeleton offrono una migliore esperienza utente riducendo la frustrazione del tempo di caricamento. Concentrandosi sui progressi anziché sui tempi di attesa, crea l'illusione per gli utenti che le informazioni verranno visualizzate in modo incrementale sullo schermo. Bill Chung nella sua ricerca lo conferma.
Che cos'è uno schermo scheletro?
Uno schermo scheletro è una versione dell'interfaccia utente che non contiene contenuto effettivo; imita invece il layout della pagina mostrando i suoi elementi in una forma simile al contenuto reale mentre viene caricato e diventa disponibile (cioè quando la latenza di rete lo consente).
Uno schermo scheletro è essenzialmente un wireframe della pagina, con caselle segnaposto per testo e immagini.
Cosa c'è di unico in uno schermo scheletro?
Un'interfaccia utente scheletrica assomiglia all'interfaccia utente effettiva della pagina, quindi gli utenti capiranno quanto velocemente verrà caricato il Web o l'app mobile anche prima che il contenuto venga visualizzato. Ecco un paio di motivi per cui potresti prendere in considerazione l'utilizzo di schermi scheletrici nel tuo prossimo progetto:
- imitare il layout di una pagina è più facile con uno schermo scheletro,
- i contenuti vengono caricati progressivamente (non tutti in una volta).
Gli schermi di scheletro sono anche indicati come:
- elementi fantasma,
- segnaposto di contenuto,
- caricatori di contenuti.
Blockchain.com, YouTube, Facebook, Medium e altre grandi aziende tecnologiche mostrano schermi scheletrici mentre i loro contenuti vengono caricati per migliorare l'esperienza utente.
Blockchain.com
medio
Tipi di schermi scheletrici
Esistono diversi tipi di schermi scheletrici. I principali sono segnaposto di testo e segnaposto di immagine (o colore).
La maggior parte degli sviluppatori preferisce utilizzare i segnaposto di testo come l'interfaccia utente dello scheletro nelle proprie pagine perché sono facili da creare e lo sviluppatore non richiede alcun dettaglio sulla sostanza del contenuto effettivo; invece lo scheletro imita l'interfaccia utente.
I segnaposto colorati sono più difficili da creare perché richiedono dettagli sul contenuto.
Alcuni pacchetti popolari semplificano l'implementazione di schermate scheletriche nelle app Web. Diamo un'occhiata più da vicino a entrambi:
- Segnaposto di reazione
- Scheletro di caricamento di reazione
Esamineremo i pro ei contro di ciascun pacchetto, prima di considerare quale utilizzare per la nostra applicazione.
Segnaposto di reazione
Professionisti
- I componenti segnaposto vengono utilizzati per creare un'interfaccia utente di scheletro personalizzata.
- È supportata l'animazione a impulsi (cioè l'effetto di movimento su un elemento).
- Viene fornito con un'API basata su componenti.
contro
- I componenti dello scheletro vengono gestiti separatamente, quindi l'aggiornamento degli stili di un componente potrebbe richiedere l'aggiornamento anche del componente dello scheletro.
- La curva di apprendimento non è lineare perché ci sono più componenti per esigenze diverse.
Quello che segue è un esempio di un componente scheletro che utilizza il pacchetto react-placeholder
:
import { TextBlock, RectShape } from 'react-placeholder/lib/placeholders'; import ReactPlaceholder from 'react-placeholder'; const GhostPlaceholder = () => ( <div className='my-placeholder'> <RectShape color='gray' style={{width: 25, height: 70}} /> <TextBlock rows={6} color='blue'/> </div> ); <ReactPlaceholder ready={ready} customPlaceholder={<GhostPlaceholder />}> <MyComponent /> </ReactPlaceholder>
Importando TextBlock
e RectShape
da react-placeholder/lib/placeholder
e ReactPlaceholder
da react-placeholder
, abbiamo creato un componente funzionale chiamato GhostPlaceholder
. GhostPlaceholder
ha un div e all'interno del div abbiamo utilizzato il componente RectShape, che descrive le dimensioni di un rettangolo, passa il valore di qualsiasi colore e definisce gli stili del rettangolo.
Successivamente, abbiamo utilizzato il componente TextBlock
per impostare i valori per le righe e il colore. Il componente TextBlock
definisce il numero di righe e il colore del testo.
Passiamo MyComponent
come figlio del componente ReactPlaceholder
, che riceve ready
e il componente GhostPlaceholder
come valori per le sue props ready
e customPlaceholder
.
Il MyComponent
verrà caricato quando viene mostrata l'interfaccia utente della schermata dello scheletro.
Per saperne di più, consulta la documentazione.
Scheletro di caricamento di reazione
Professionisti
- È basato su API e ha un componente con prop per tutte le personalizzazioni.
- Può essere utilizzato come componente dello scheletro separato e anche direttamente all'interno di qualsiasi componente, quindi è flessibile.
- Supporta temi e animazione Pulse.
contro
- È facile da implementare per un'interfaccia utente di scheletro semplice, ma complicato per scheletri più complessi.
- Avere un componente scheletro separato renderà più difficile la manutenzione quando l'interfaccia utente e gli stili cambiano.
Quello che segue è un esempio di React Loading Skeleton:
import Skeleton, { SkeletonTheme } from "react-loading-skeleton"; const SkeletonComponent = () => ( <SkeletonTheme color="#202020" highlightColor="#444"> <section> <Skeleton height={50} width={50} /> </section> </SkeletonTheme> );
Abbiamo importato Skeleton
e SkeletonTheme
dalla libreria react-loading-skeleton
, quindi abbiamo creato un componente funzionale che esegue il rendering del componente SkeletonTheme
, con color
e hightlightColor
come proprietà.
Il componente SkeletonTheme
viene utilizzato per la creazione di temi (ad esempio, l'aggiunta di effetti di colore all'interfaccia utente dello scheletro).
Infine, all'interno della sezione, definiamo il componente Skeleton
, con le proprietà di altezza e larghezza e i relativi valori passati.
Creazione di un'interfaccia utente dello schermo scheletro simile a YouTube
Creiamo una schermata dello scheletro simile a YouTube, utilizzando React Loading Skeleton, per mostrare come funziona un'interfaccia utente dello scheletro.
Imposta Reagire
Il modo più semplice per configurare React è utilizzare Create React App, che è "un modo ufficialmente supportato per creare applicazioni React a pagina singola. Offre una configurazione di build moderna senza alcuna configurazione.
Lo useremo per avviare l'applicazione che creeremo. Dal tuo terminale, esegui il comando seguente:
npx create-react-app skeleton-screens && cd skeleton-screens
Una volta completata l'installazione, avviare il server React eseguendo npm start
:
Crea l'interfaccia utente di YouTube senza uno schermo scheletro
Innanzitutto, inseriamo i dati fittizi di YouTube. Gli endpoint reali verrebbero normalmente utilizzati al posto dei dati fittizi, ma in questo tutorial utilizzeremo dati fittizi.
Crea un file nella tua cartella src/
e data.js
, aggiungi il codice seguente.
const dummyData= [ { section: "Recommended", channel: "CNN", items: [ { id: "fDObf2AeAP4", image: "https://img.youtube.com/vi/fDObf2AeAP4/maxresdefault.jpg", title: "75 million Americans ordered to stay home", views: "1.9M views", published: "3 days agos" }, { id: "3AzIgAa0Cm8", image: "https://img.youtube.com/vi/3AzIgAa0Cm8/maxresdefault.jpg", title: "Gupta: The truth about using chloroquine to fight coronavirus pandemic", views: "128K views", published: "4 hours ago" }, { id: "92B37aXykYw", image: "https://img.youtube.com/vi/92B37aXykYw/maxresdefault.jpg", title: "Willie Jones STUNS Simon Cowell In Pitch Perfect Performance of 'Your Man'!", views: "2.47 million views", published: "1 month ago" }, { id: "J6rVaFzOEP8", image: "https://img.youtube.com/vi/J6rVaFzOEP8/maxresdefault.jpg", title: "Guide To Becoming A Self-Taught Software Developer", views: "104K views", published: "17 days ago" }, { id: "Wbk8ZrfU3EM", image: "https://img.youtube.com/vi/Wbk8ZrfU3EM/maxresdefault.jpg", title: "Tom Hanks and Rita Wilson test positive for coronavirus", views: "600k views", published: "1 week ago" }, { id: "ikHpFgKJax8", image: "https://img.youtube.com/vi/ikHpFgKJax8/maxresdefault.jpg", title: "Faces Of Africa- The Jerry Rawlings story", views: "2.3 million views", published: "2014" } ] }, { section: "Breaking News", channel: "CGTN America", items: [ { id: "tRLDPy1A8pI", image: "https://img.youtube.com/vi/tRLDPy1A8pI/maxresdefault.jpg", title: "Is Trump blaming China for COVID-19? You decide.", views: "876k views", published: "9 days ago" }, { id: "2ulH1R9hlG8", image: "https://img.youtube.com/vi/2ulH1R9hlG8/maxresdefault.jpg", title: "Journalist still goes to office during pandemic, see her daily routine", views: "873 views", published: "3 hours ago" }, { id: "TkfQ9MaIgU", image: "https://img.youtube.com/vi/_TkfQ9MaIgU/maxresdefault.jpg", title: "How are small businesses going to survive the economic downturn of the COVID-19 era?", views: "283 views", published: "4 day ago" } ] } ]; export default dummyData;
Per replicare il formato di YouTube, abbiamo creato dati fittizi con una serie di oggetti, con proprietà come ID, immagine, titolo, numero di visualizzazioni e data di pubblicazione.
Quindi, creiamo la nostra interfaccia utente di YouTube. Avremo tre componenti:
Card | Contiene i dettagli della miniatura, del titolo, del numero di visualizzazioni, della data di pubblicazione e del canale del video. |
CardList | Restituisce tutte le carte di seguito. |
App | Monta il nostro oggetto dummyData , carica l'interfaccia utente dello scheletro per due secondi e restituisce il componente CardList . |
All'interno della tua cartella src
, crea una cartella e chiamala components
. All'interno della cartella dei components
, crea un file Card.js
, aggiungi il seguente codice:
import React from "react"; const Card = ({ item, channel }) => { return ( <li className="card"> <a href={`https://www.youtube.com/watch?v=${item.id}`} target="_blank" rel="noopener noreferrer" className="card-link" > <img src={item.image} alt={item.title} className="card-image" /> <img src={item.image} alt={item.title} className="channel-image" /> <h4 className="card-title">{item.title}</h4> <p className="card-channel"> <i>{channel}</i> </p> <div className="card-metrics"> {item.views} • {item.published} </div> </a> </li> ); }; export default Card;
Abbiamo creato un componente Card
. Al suo interno, abbiamo importato React
da react
e abbiamo decostruito l' item
e channel
oggetti di scena in modo che possano essere utilizzati attraverso il componente Card
. Ciascun componente dell'elemento della Card
che visualizza un video mostrerà la miniatura, il numero di visualizzazioni, la data di pubblicazione e il titolo.
Componente Elenco Carte
All'interno della cartella dei components
, crea un file CardList.js e aggiungi il seguente codice:
import React from "react"; import Card from "./Card"; const CardList = ({ list }) => { return ( <ul className="list"> {list.items.map((item, index) => { return <Card key={index} item={item} channel={list.channel} />; })} </ul> ); }; export default CardList;
In questo componente, abbiamo importato il componente Card
che abbiamo creato. La carta accetta gli item
di scena e gli oggetti di scena, che list.items
channel
Quindi esportiamo questo componente come CardList
, perché lo utilizzeremo nel nostro componente App
.
Nota : l'array di elementi mappato in questo componente è l'array di oggetti nel nostro dummyData
.
Componente dell'app
All'interno del file app.js nella directory src/
, elimina il codice presente e aggiungi quanto segue.
import React, { useState, useEffect } from "react"; import "./App.css"; import dummyData from "./data"; import CardList from "./components/CardList"; const App = () => { const [videos, setVideos] = useState([]); const [loading, setLoading] = useState(false); useEffect(() => { setLoading(true); const timer = setTimeout(() => { setVideos(dummyData); setLoading(false); }, 5000); return () => clearTimeout(timer); }, []); return ( <div className="App"> { videos.map((list, index) => { return ( <section key={index}> <h2 className="section-title">{list.section}</h2> <CardList list={list} /> <hr /> </section> ); })} </div> ); }; export default App;
In questo componente, abbiamo importato gli useState
e useEffect
insieme a React
e agli altri file che abbiamo creato e che saranno necessari nel componente App
.
Poiché i nostri dati sono dati fittizi, dobbiamo simularli come i dati API caricando il contenuto dopo un timeout di due secondi, utilizzando il metodo JavaScript setTimeout
.
Successivamente, nel componente App
, creiamo uno stato video e impostiamo lo stato su un array vuoto usando useState
.
Per caricare i nostri dati fittizi, useremo l'hook useEffect
. Nel nostro hook creiamo un timer variabile che contiene la funzione setTimeout
()
. All'interno della funzione, impostiamo il nostro stato video sul nostro oggetto dummyData
e ci assicuriamo che i dati vengano caricati dopo due secondi e, infine, annulliamo il timer durante lo smontaggio.
Infine, mappiamo attraverso il nostro stato video e restituiamo l'elemento della sezione che contiene la list-section
e il componente CardList
con i suoi oggetti di scena.
Aggiunta CSS
Fino ad ora, abbiamo usato molte classi senza un vero CSS. All'interno della cartella src
, elimina tutto in App.css
e sostituiscilo con il seguente codice;
.App { max-width: 960px; margin: 0 auto; font-size: 16px; } .list { display: flex; justify-content: space-between; flex-wrap: wrap; list-style: none; padding: 0; } .section-title { margin-top: 30px; } .card { width: calc(33% - 10px); margin: 20px 0; } .card-link { color: inherit; text-decoration: none; } .card-image { width: 100%; } .channel-image { border-radius: 100%; padding: 0, 10px, 0, 0; width: 40px; height: 40px; } .card-title { margin-top: 10px; margin-bottom: 0; } .card-channel { margin-top: 5px; margin-bottom: 5px; font-size: 14px; } /* Tablets */ @media (max-width: 1000px) { .App { max-width: 600px; } .card { width: calc(50% - 22px); } } /* Mobiles \*/ @media (max-width: 640px) { .App { max-width: 100%; padding: 0 15px; } .card { width: 100%; } }
Vediamo come appare la nostra interfaccia utente di YouTube senza lo schermo dello scheletro. Puoi vedere che quando la pagina viene caricata, viene visualizzata una schermata bianca per due secondi, quindi i dati vengono caricati prontamente.
Utilizzo dello scheletro di caricamento di React
A differenza di altre librerie in cui creeresti meticolosamente uno schermo scheletro per abbinare le dimensioni dei caratteri, l'altezza delle linee e i margini del tuo contenuto, il componente Skeleton
è progettato per essere utilizzato direttamente nei tuoi componenti, al posto del contenuto che sta caricando.
Esaminiamo alcuni motivi per cui abbiamo scelto React Loading Skeleton rispetto ad altri.
Temi
React Loading Skeleton supporta i temi. Pertanto, puoi facilmente cambiare i colori di tutti i componenti dello scheletro usando SkeletonTheme
e passare i valori agli props
di scena del colore.
Di seguito è riportato un esempio che mostra come funziona:
import Skeleton, { SkeletonTheme } from "react-loading-skeleton"; <SkeletonTheme color="grey" highlightColor="#444"> <p> <Skeleton height={250} width={300} count={1} /> </p> </SkeletonTheme> <SkeletonTheme color="#990" highlightColor="#550"> <p> <Skeleton height={250} width={300} count={1} /> </p> </SkeletonTheme>
Durata
Oltre height
, width
e color
, possiamo anche specificare una duration
.
<Skeleton duration={2} />
La durata predefinita è 1.2
. Questo determina quanto tempo ci vuole per eseguire un ciclo dell'animazione dello scheletro.
Per saperne di più, consulta la documentazione.
Implementazione dell'interfaccia utente dello schermo scheletro
Ora installeremo react-loading-skeleton
. Esegui il seguente comando nel tuo terminale per installare il pacchetto:
npm install react-loading-skeleton
Componente scheletro
Creiamo un componente scheletro per i nostri dati video. All'interno della nostra cartella components
, crea un file SkeletonCard.js
e aggiungi il seguente codice:
import React from "react"; import Skeleton from "react-loading-skeleton"; const SkeletonCard = () => { return ( <section> <h2 className="section-title"> <Skeleton height={30} width={300} /> </h2> <ul className="list"> {Array(9) .fill() .map((item, index) => ( <li className="card" key={index}> <Skeleton height={180} /> <h4 className="card-title"> <Skeleton circle={true} height={50} width={50} /> <Skeleton height={36} width={`80%`} /> </h4> <p className="card-channel"> <Skeleton width={`60%`} /> </p> <div className="card-metrics"> <Skeleton width={`90%`} /> </div> </li> ))} </ul> </section> ); }; export default SkeletonCard;
Abbiamo creato una lista non ordinata. Al suo interno, abbiamo utilizzato il metodo Array.fill()
. Poiché abbiamo nove elementi di dati fittizi, abbiamo utilizzato il metodo Array.fill()
per scorrere la lunghezza del nostro oggetto items
e lo abbiamo riempito senza alcun valore di indice, rendendo quindi il nostro array vuoto . Consulta la documentazione di Array.fill per sapere come funziona.
Successivamente, abbiamo mappato il nostro array vuoto per restituire un elenco contenente le proprietà dello scheletro e abbiamo specificato il valore di ciascuna delle proprietà dello scheletro.
Qui, l' height
connota la lunghezza di un rettangolo dello scheletro e la width
si riferisce all'ampiezza, mentre il circle
crea la parte arrotondata dell'interfaccia utente dello scheletro.
React Loading Skeleton viene fornito con l'animazione Pulse predefinita, il che lo rende a portata di mano. Potresti creare un'animazione Pulse per adattarla al tuo progetto, ma se me lo chiedi, rimarrei con l'impostazione predefinita.
Finalmente è disponibile il codice sorgente completo.
Ora abbiamo un'interfaccia utente dello scheletro completamente funzionale. Il nostro esempio mostra lo scheletro per cinque secondi prima di mostrare il contenuto.
Vediamo il nostro risultato finora:
Conclusione
Gli schermi Skeleton migliorano enormemente l'esperienza dell'utente evitando la frustrazione di dover affrontare uno schermo completamente vuoto e dando all'utente un'idea dell'aspetto del contenuto prima del caricamento.
Se non ti senti a tuo agio con nessuno dei pacchetti che abbiamo esaminato, puoi creare la tua interfaccia utente scheletrica creando rettangoli e cerchi che imitano il layout della pagina.
Si prega di condividere il tuo feedback e la tua esperienza nella sezione commenti qui sotto. Mi piacerebbe vedere cosa ti viene in mente!
Il repository di supporto per questo articolo è disponibile su Github.
Riferimenti
- "Tutto quello che devi sapere sugli schermi Skeleton", Bill Chung, UX Collective
- "Scheletro che carica pagine con React", Anthony Panagi, Octopus Wealth
- "Scheletri scheletrici con React and React Native", Chris Dolphin, Alligator.io
- "Implementazione del caricamento dello scheletro in reazione", Adrian Bece, DEV