React'te İskelet Ekranlarını Uygulamak
Yayınlanan: 2022-03-10Döndürücüler ve yükleyiciler, geleneksel olarak kullanıcılara içeriğin yüklenmesinin biraz zaman alacağını söylemenin yolu olmuştur. Bu yaklaşım harika olsa da, modern gelişimde hızla modası geçiyor. İskelet ekranlar, bekleme süreleri yerine ilerlemeye odaklandıkları ve dolayısıyla yükleme süresi sıkıntısını azalttığı için geleneksel yükleyiciler için mükemmel bir yedek haline geliyor.
Bu makalede, CSS React veya JavaScript sözdiziminin temellerini ele almayacağız, bu nedenle takip etmek için bu dillerden herhangi birinde uzman olmanıza gerek yok.
UI ve UX uzmanları bize, kullanıcılar bir sayfada içeriğin yüklenmesini beklerken onları etkileşimde tutmamız gerektiğini öğretiyor.
İçerik yüklenmeden önce kullanıcılarla etkileşim kurmak için döndürücüleri kullanmanın ardındaki fikir harika; ancak sonuç idealden daha az olabilir çünkü çoğu kullanıcı bir saatmiş gibi yapay bir animasyonlu çarka bakmaktan sıkılır. Luke Wroblewski bunu detaylandırıyor.
İskelet ekranlar, yükleme süresi sıkıntısını azaltarak daha iyi bir kullanıcı deneyimi sunar. Bekleme süreleri yerine ilerlemeye odaklanarak, kullanıcılar için bilgilerin ekranda kademeli olarak görüntüleneceği yanılsamasını yaratır. Bill Chung araştırmasında bunu doğruluyor.
İskelet Ekran Nedir?
İskelet ekran, gerçek içerik içermeyen kullanıcı arayüzünün bir sürümüdür; bunun yerine, yüklenirken ve kullanılabilir hale geldiğinde (yani ağ gecikmesi izin verdiğinde) öğelerini gerçek içeriğe benzer bir şekilde göstererek sayfanın düzenini taklit eder.
Bir iskelet ekran, metin ve resimler için yer tutucu kutuları olan, esasen sayfanın bir tel çerçevesidir.
Bir İskelet Ekranının Benzersiz Olması Nedir?
Bir iskelet kullanıcı arayüzü, sayfanın gerçek kullanıcı arayüzüne benzer, böylece kullanıcılar, web veya mobil uygulamanın ne kadar hızlı yükleneceğini, içerik görünmeden önce bile anlar. Bir sonraki projenizde iskelet ekranları kullanmayı düşünmek isteyebileceğiniz birkaç neden:
- bir sayfanın düzenini taklit etmek, bir iskelet ekranla daha kolaydır,
- içerik aşamalı olarak yüklenir (tümü aynı anda değil).
İskelet ekranlara ayrıca şu adlar da verilir:
- hayalet öğeler,
- içerik yer tutucuları,
- içerik yükleyiciler
Blockchain.com, YouTube, Facebook, Medium ve diğer büyük teknoloji şirketleri, UX'i artırmak için içerikleri yüklenirken iskelet ekranlar görüntüler.
Blockchain.com
Orta
İskelet Ekran Çeşitleri
Farklı türde iskelet ekranları vardır. Başlıcaları metin yer tutucuları ve resim (veya renk) yer tutucularıdır.
Çoğu geliştirici, oluşturmaları kolay olduğundan ve geliştirici gerçek içeriğin özü hakkında herhangi bir ayrıntıya ihtiyaç duymadığından sayfalarında iskelet kullanıcı arayüzü olarak metin yer tutucularını kullanmayı tercih eder; bunun yerine iskelet, kullanıcı arayüzünü taklit eder.
İçerikle ilgili ayrıntılar gerektirdiğinden, renk yer tutucularının oluşturulması daha zordur.
Bazı popüler paketler, web uygulamalarında iskelet ekranların uygulanmasını kolaylaştırır. Her ikisine de daha yakından bakalım:
- Tepki Yer Tutucu
- Tepki Yükleme İskeleti
Uygulamamız için hangisini kullanacağımızı düşünmeden önce her paketin artılarına ve eksilerine bakacağız.
Tepki Yer Tutucu
Artıları
- Yer tutucu bileşenleri, özel bir iskelet kullanıcı arabirimi oluşturmak için kullanılır.
- Darbe animasyonu (yani bir öğe üzerindeki hareket efekti) desteklenir.
- Bileşen tabanlı bir API ile birlikte gelir.
Eksileri
- İskelet bileşenleri ayrı olarak korunur, bu nedenle bir bileşenin stillerinin güncellenmesi muhtemelen iskelet bileşeninin de güncellenmesini gerektirir.
- Öğrenme eğrisi doğrusal değildir çünkü farklı ihtiyaçlar için birden fazla bileşen vardır.
Aşağıdaki, react-placeholder
paketini kullanan bir iskelet bileşeni örneğidir:
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>
TextBlock
ve RectShape
react-placeholder/lib/placeholder
ve ReactPlaceholder
react-placeholder
tutucudan içe aktararak GhostPlaceholder
adlı işlevsel bir bileşen oluşturduk. GhostPlaceholder
bir div'i vardır ve div'in içinde bir dikdörtgenin boyutlarını tanımlayan, herhangi bir rengin değerini ileten ve dikdörtgenin stillerini tanımlayan RectShape bileşenini kullandık.
Daha sonra, satır ve renk değerlerini ayarlamak için TextBlock
bileşenini kullandık. TextBlock
bileşeni, metnin satır sayısını ve rengini tanımlar.
MyComponent
, ready
ve ready
destekleri için değerler olarak GhostPlaceholder
bileşenini alan ReactPlaceholder
bileşeninin bir çocuğu olarak customPlaceholder
.
MyComponent
, iskelet ekranı UI gösterildiğinde yüklenecektir.
Daha fazla bilgi edinmek için belgelere bakın.
Tepki Yükleme İskeleti
Artıları
- API tabanlıdır ve tüm özelleştirmeler için aksesuarlara sahip tek bir bileşene sahiptir.
- Ayrı bir iskelet bileşeni olarak ve ayrıca herhangi bir bileşenin içinde doğrudan kullanılabilir, bu nedenle esnektir.
- Tema oluşturmayı ve Darbe animasyonunu destekler.
Eksileri
- Basit bir iskelet kullanıcı arayüzü için uygulanması kolaydır, ancak daha karmaşık iskeletler için karmaşıktır.
- Ayrı bir iskelet bileşenine sahip olmak, kullanıcı arayüzü ve stiller değiştiğinde bakımı zorlaştıracaktır.
Aşağıdaki, React Loading Skeleton'un bir örneğidir:
import Skeleton, { SkeletonTheme } from "react-loading-skeleton"; const SkeletonComponent = () => ( <SkeletonTheme color="#202020" highlightColor="#444"> <section> <Skeleton height={50} width={50} /> </section> </SkeletonTheme> );
react-loading-skeleton
kitaplığından Skeleton
ve SkeletonTheme
içe aktardık, ardından color
ve hightlightColor
özellikleriyle SkeletonTheme
bileşenini oluşturan işlevsel bir bileşen oluşturduk.
SkeletonTheme
bileşeni, tema oluşturmak için kullanılır (örneğin, iskelet kullanıcı arayüzüne renk efektleri ekleme).
Son olarak, bölüm içinde, yükseklik ve genişlik özellikleri ve bunların uygun değerleri iletilmiş olan Skeleton
bileşenini tanımlıyoruz.
YouTube Benzeri Bir İskelet Ekran Kullanıcı Arayüzü Oluşturma
Bir iskelet kullanıcı arayüzünün nasıl çalıştığını göstermek için React Loading Skeleton kullanarak YouTube benzeri bir iskelet ekranı oluşturalım.
React'i Ayarla
React'i kurmanın en kolay yolu, "tek sayfalı React uygulamaları oluşturmanın resmi olarak desteklenen bir yolu" olan Create React App'i kullanmaktır. Konfigürasyon gerektirmeyen modern bir yapı kurulumu sunuyor.”
Oluşturacağımız uygulamayı önyüklemek için kullanacağız. Terminalinizden aşağıdaki komutu çalıştırın:
npx create-react-app skeleton-screens && cd skeleton-screens
Kurulum tamamlandıktan sonra, npm start
çalıştırarak React sunucusunu başlatın:
İskelet Ekranı Olmadan YouTube Kullanıcı Arayüzü Oluşturun
İlk olarak, YouTube kukla verilerini girelim. Normalde kukla veriler yerine gerçek uç noktalar kullanılır, ancak bu eğitimde kukla verileri kullanacağız.
src/
klasörünüzde bir dosya oluşturun ve data.js
olarak adlandırın, aşağıdaki kodu ekleyin.
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;
YouTube'un biçimini kopyalamak için kimlik, resim, başlık, görüntüleme sayısı ve yayın tarihi gibi özelliklere sahip bir dizi nesneye sahip yapay veriler oluşturduk.
Ardından, YouTube UI'mizi oluşturalım. Üç bileşenimiz olacak:
Card | Videonun küçük resminin, başlığının, görüntülenme sayısının, yayın tarihinin ve kanalının ayrıntılarını içerir. |
CardList | Tüm kartları arka arkaya döndürür. |
App | dummyData , iki saniye için iskelet kullanıcı arabirimini yükler ve CardList bileşenini döndürür. |
src
klasörünüzün içinde bir klasör oluşturun ve onu components
olarak adlandırın. components
klasörünün içinde bir Card.js
dosyası oluşturun ve buna aşağıdaki kodu ekleyin:
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;
Bir Card
bileşeni oluşturduk. Bunun içinde, react
öğesinden React
içe aktardık ve Card
bileşeninde kullanılabilecekleri şekilde item
ve channel
aksesuarlarını bozduk. Bir video görüntüleyen her Card
öğesi bileşeni, küçük resmi, görüntüleme sayısını, yayın tarihini ve başlığı gösterir.
CardList Bileşeni
components
klasörünün içinde bir CardList.js dosyası oluşturun ve buna aşağıdaki kodu ekleyin:
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;
Bu bileşende, oluşturduğumuz Card
bileşenini içe aktardık. Kart, list.items
aracılığıyla eşleştirerek elde ettiğimiz item
ve channel
aksesuarlarını kabul eder. Daha sonra bu bileşeni CardList
olarak dışa aktarırız çünkü onu App
bileşenimizde kullanacağız.
Not : Bu bileşende eşlenen öğeler dizisi, dummyData
nesnelerin dizisidir.
Uygulama Bileşeni
src/
dizinindeki app.js dosyasının içinde orada bulunan kodu silin ve aşağıdakini ekleyin.
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;
Bu bileşende, React
ve oluşturduğumuz ve App
bileşeninde gerekli olacak diğer dosyaların yanı sıra useState
ve useEffect
kancalarını içe aktardık.
Verilerimiz yapay veriler olduğundan, JavaScript setTimeout
yöntemini kullanarak içeriği iki saniyelik bir zaman aşımından sonra yükleyerek API verileri gibi taklit etmemiz gerekir.
Ardından, App
bileşeninde bir video durumu oluşturuyoruz ve durumu useState
kullanarak boş bir diziye ayarlıyoruz.
Sahte verilerimizi yüklemek için useEffect
kancasını kullanacağız. Kancamızda, setTimeout
()
işlevini tutan değişken bir zamanlayıcı oluşturuyoruz. Fonksiyon içerisinde video durumumuzu dummyData
ve verilerin iki saniye sonra yüklenmesini sağlıyoruz ve son olarak demonte ederken timer'ı iptal ediyoruz.
Son olarak, video durumumuzla eşleşiriz ve list-section
içeren bölüm öğesini ve liste destekleriyle CardList
bileşenini döndürürüz.
CSS ekleme
Şimdiye kadar, gerçek CSS'siz birçok sınıf kullandık. src
klasörünün içinde, App.css
içindeki her şeyi silin ve aşağıdaki kodla değiştirin;
.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%; } }
Bakalım iskelet ekran olmadan YouTube kullanıcı arayüzümüz nasıl görünüyor. Sayfa yüklendiğinde, iki saniye boyunca beyaz bir ekranın göründüğünü ve ardından verilerin hemen yüklendiğini görebilirsiniz.
Tepki Yükleme İskeletini Kullanma
İçeriğinizin yazı tipi boyutlarına, satır yüksekliklerine ve kenar boşluklarına uyması için titizlikle bir iskelet ekran oluşturacağınız diğer kitaplıkların aksine, Skeleton
bileşeni, yüklenen içeriğin yerine doğrudan bileşenlerinizde kullanılmak üzere tasarlanmıştır.
Diğerleri yerine React Loading Skeleton'ı seçmemizin birkaç nedenini gözden geçirelim.
Temalandırma
React Loading Skeleton tema oluşturmayı destekler. Böylece SkeletonTheme
kullanarak tüm iskelet bileşenlerinin renklerini kolayca değiştirebilir ve renk props
değerler iletebilirsiniz.
Aşağıda nasıl çalıştığını gösteren bir örnek verilmiştir:
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>
Süre
height
, width
ve color
unsurlarına ek olarak, bir duration
unsuru da belirtebiliriz.
<Skeleton duration={2} />
Süre varsayılan olarak 1.2
. Bu, iskelet animasyonunun bir döngüsünün ne kadar süreceğini belirler.
Daha fazla bilgi edinmek için belgelere bakın.
İskelet Ekranı Kullanıcı Arayüzü Uygulama
Şimdi, react-loading-skeleton
. Paketi kurmak için terminalinizde aşağıdaki komutu çalıştırın:
npm install react-loading-skeleton
İskelet Bileşeni
Video verilerimiz için bir iskelet bileşeni oluşturalım. components
klasörümüzün içinde bir SkeletonCard.js
dosyası oluşturun ve aşağıdaki kodu ekleyin:
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;
Sırasız bir liste oluşturduk. Bunun içinde Array.fill()
yöntemini kullandık. Dokuz yapay veri öğemiz olduğundan, items
nesnemizin uzunluğu boyunca döngü yapmak için Array.fill()
yöntemini kullandık ve onu dizin değeri olmadan doldurduk, bu nedenle dizimizi boş hale getirdik. Nasıl çalıştığını öğrenmek için Array.fill belgelerine bakın.
Daha sonra, iskelet özelliklerini içeren bir liste döndürmek için boş dizimizi eşledik ve her bir iskelet özelliğinin değerini belirledik.
Burada height
, bir iskelet dikdörtgeninin uzunluğunu ifade eder ve width
, genişliği ifade ederken, circle
, iskelet kullanıcı arayüzünün yuvarlak kısmını oluşturur.
React Loading Skeleton, varsayılan Pulse animasyonu ile birlikte gelir, bu da onu kullanışlı kılar. Projenize uyacak şekilde Darbe animasyonu oluşturabilirsiniz, ancak bana sorarsanız varsayılana sadık kalırdım.
Son olarak, tam kaynak kodu mevcuttur.
Artık tamamen işlevsel bir iskelet ekran kullanıcı arayüzüne sahibiz. Örneğimiz, içeriği göstermeden önce iskeleti beş saniye gösterir.
Şimdiye kadarki sonucumuzu görelim:
Çözüm
İskelet ekranlar, tamamen boş bir ekranla karşı karşıya kalmanın yarattığı hayal kırıklığını önleyerek ve kullanıcıya içeriğin yüklenmeden önce nasıl görüneceğine dair bir izlenim vererek kullanıcı deneyimini büyük ölçüde geliştirir.
İncelediğimiz paketlerin hiçbirinden memnun değilseniz, sayfa düzenini taklit eden dikdörtgenler ve daireler oluşturarak kendi iskelet kullanıcı arayüzünüzü oluşturabilirsiniz.
Lütfen geri bildiriminizi ve deneyiminizi aşağıdaki yorumlar bölümünde paylaşın. Ne bulduğunu görmek isterim!
Bu makalenin destekleyici deposu Github'da mevcuttur.
Referanslar
- “İskelet Ekranları Hakkında Bilmeniz Gereken Her Şey”, Bill Chung, UX Collective
- “React ile İskelet Yükleme Sayfaları”, Anthony Panagi, Octopus Wealth
- “React And React Native ile İskelet Ekranlar”, Chris Dolphin, Alligator.io
- “React'te İskelet Yüklemesinin Uygulanması”, Adrian Bece, DEV