Reactでのスケルトンスクリーンの実装

公開: 2022-03-10
クイックサマリー↬このチュートリアルでは、スケルトンスクリーンUIとは何か、スケルトンスクリーンライブラリのいくつかのタイプ、およびそれらの長所と短所を学習します。 React Loading Skeletonを使用して、YouTubeのようなスケルトン画面UIを構築します。 次に、選択したスケルトン画面のReactパッケージを自分で試すことができます。

スピナーとローダーは、従来、コンテンツの読み込みに時間がかかることをユーザーに通知する方法でした。 このアプローチは素晴らしいものですが、現代の開発では急速に時代遅れになりつつあります。 スケルトンスクリーンは、待機時間ではなく進行状況に重点を置いているため、従来のローダーの完全な代替品になりつつあり、ロード時間のフラストレーションを軽減します。

この記事では、CSS ReactまたはJavaScript構文の基本については説明しません。したがって、これらの言語のいずれかの専門家である必要はありません。

ローダーとスケルトン画面UIの違い
ローダーとスケルトン画面UIの違い(大プレビュー)

UIとUXの専門家は、ユーザーがコンテンツがページに読み込まれるのを待つ間、ユーザーの関心を維持する必要があると教えています。

コンテンツが読み込まれる前にスピナーを使用してユーザーを引き付ける背後にある考え方は素晴らしいです。 ただし、ほとんどのユーザーは、時計のようにダミーのアニメーションスピナーを見つめるのに飽きてしまうため、結果は理想的とは言えません。 ルーク・ウロブレフスキーはこれについて詳しく述べています。

スケルトンスクリーンは、読み込み時のフラストレーションを減らすことで、より優れたユーザーエクスペリエンスを提供します。 待ち時間ではなく進行状況に焦点を当てることで、情報が画面に段階的に表示されるという錯覚をユーザーにもたらします。 ビル・チョンは彼の研究でこれを確認しています。

スケルトンスクリーンとは何ですか?

スケルトン画面は、実際のコンテンツを含まないUIのバージョンです。 代わりに、ページが読み込まれて利用可能になるとき(つまり、ネットワーク遅延が許す場合)に、実際のコンテンツに似た形で要素を表示することにより、ページのレイアウトを模倣します。

スケルトン画面は基本的にページのワイヤーフレームであり、テキストと画像用のプレースホルダーボックスがあります。

ジャンプした後もっと! 以下を読み続けてください↓

スケルトンスクリーンのユニークな点は何ですか?

スケルトンUIはページの実際のUIに似ているため、ユーザーは、コンテンツが表示される前であっても、Webまたはモバイルアプリがどれだけ速く読み込まれるかを理解できます。 次のプロジェクトでスケルトンスクリーンの使用を検討する理由は次のとおりです。

  • スケルトン画面を使用すると、ページのレイアウトを模倣するのが簡単になります。
  • コンテンツは段階的に読み込まれます(一度にすべてではありません)。

スケルトンスクリーンは、次のようにも呼ばれます。

  • ゴースト要素、
  • コンテンツプレースホルダー、
  • コンテンツローダー。

Blockchain.com、YouTube、Facebook、Medium、およびその他の大手テクノロジー企業は、コンテンツが読み込まれている間、スケルトン画面を表示してUXを向上させます。

Blockchain.com

Blockchain.comスケルトン画面UI
Blockchain.comの部分的にロードされた状態(グラフ分析でスケルトンがどのように使用されているかに注意してください)(大プレビュー)

中くらい

ミディアムスケルトン画面UI
MediumのスケルトンUI(大プレビュー)

LinkedIn

LinkedInスケルトン画面UI
2018年のLinkedInのホームフィードの読み込み状態(大プレビュー)

スケルトンスクリーンの種類

スケルトンスクリーンにはさまざまな種類があります。 主なものは、テキストプレースホルダーと画像(またはカラー)プレースホルダーです。

ほとんどの開発者は、テキストプレースホルダーをページのスケルトンUIとして使用することを好みます。これは、テキストプレースホルダーが簡単に作成でき、実際のコンテンツの内容に関する詳細を必要としないためです。 代わりに、スケルトンはUIを模倣します。

カラープレースホルダーは、コンテンツに関する詳細が必要なため、作成が困難です。

人気のあるパッケージの中には、Webアプリでのスケルトン画面の実装を容易にするものがあります。 それらの両方を詳しく見てみましょう:

  • Reactプレースホルダー
  • Reactローディングスケルトン

アプリケーションにどちらを使用するかを検討する前に、各パッケージの長所と短所を確認します。

Reactプレースホルダー

長所

  • プレースホルダーコンポーネントは、カスタムスケルトンUIを作成するために使用されます。
  • パルスアニメーション(つまり、要素のモーション効果)がサポートされています。
  • コンポーネントベースのAPIが付属しています。

短所

  • スケルトンコンポーネントは個別に管理されるため、コンポーネントのスタイルを更新するには、スケルトンコンポーネントも更新する必要がある場合があります。
  • さまざまなニーズに対応する複数のコンポーネントがあるため、学習曲線は線形ではありません。

以下は、 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>

React react-placeholder/lib/placeholderからTextBlockRectShapeをインポートし、react react-placeholder placeholderからReactPlaceholderをインポートして、 ReactPlaceholderという名前の機能コンポーネントを作成しGhostPlaceholderた。 GhostPlaceholderにはdivがあり、div内では、長方形の寸法を記述し、任意の色の値を渡し、長方形のスタイルを定義するRectShapeコンポーネントを使用しました。

次に、 TextBlockコンポーネントを使用して、行と色の値を設定しました。 TextBlockコンポーネントは、行数とテキストの色を定義します。

MyComponentReactPlaceholderコンポーネントの子として渡します。これは、 readyおよびGhostPlaceholderコンポーネントをreadyおよびcustomPlaceholderプロップの値として受け取ります。

スケルトン画面のUIが表示されると、 MyComponentがロードされます。

詳細については、ドキュメントを確認してください。

Reactローディングスケルトン

長所

  • これはAPIベースであり、すべてのカスタマイズ用の小道具を備えた1つのコンポーネントがあります。
  • 個別のスケルトンコンポーネントとして使用することも、任意のコンポーネント内で直接使用することもできるため、柔軟性があります。
  • テーマ設定とパルスアニメーションをサポートしています。

短所

  • 単純なスケルトンUIの実装は簡単ですが、より複雑なスケルトンの実装は複雑です。
  • 個別のスケルトンコンポーネントがあると、UIとスタイルが変更されたときに保守が難しくなります。

以下は、React LoadingSkeletonの例です。

 import Skeleton, { SkeletonTheme } from "react-loading-skeleton"; const SkeletonComponent = () => ( <SkeletonTheme color="#202020" highlightColor="#444"> <section> <Skeleton height={50} width={50} /> </section> </SkeletonTheme> );

SkeletonSkeletonThemereact-loading-skeletonライブラリからインポートし、 colorhightlightColorをプロパティとして使用して、 SkeletonThemeコンポーネントをレンダリングする機能コンポーネントを作成しました。

SkeletonThemeコンポーネントは、テーマ設定に使用されます(たとえば、スケルトンUIにカラーエフェクトを追加します)。

最後に、セクション内で、高さと幅のプロパティとそれらの適切な値が渡されたSkeletonコンポーネントを定義します。

YouTubeのようなスケルトンスクリーンUIの構築

React Loading Skeletonを使用してYouTubeのようなスケルトン画面を作成し、スケルトンUIがどのように機能するかを示しましょう。

Reactを設定する

Reactを設定する最も簡単な方法は、Create React Appを使用することです。これは、「単一ページのReactアプリケーションを作成するために公式にサポートされている方法です。 構成なしの最新のビルドセットアップを提供します。」

これを使用して、構築するアプリケーションをブートストラップします。 ターミナルから、以下のコマンドを実行します。

 npx create-react-app skeleton-screens && cd skeleton-screens

インストールが完了したら、npmstartを実行してReactサーバーをnpm startします。

Reactアプリ-ScaffoldReactアプリ
Reactウェルカムページ(大きなプレビュー)

スケルトン画面なしでYouTubeUIを作成する

まず、YouTubeのダミーデータを入力しましょう。 通常、ダミーデータの代わりに実際のエンドポイントが使用されますが、このチュートリアルではダミーデータを使用します。

src/フォルダーにファイルを作成し、 data.jsという名前を付けて、次のコードを追加します。

 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の形式を複製するために、ID、画像、タイトル、再生回数、公開日などのプロパティを持つオブジェクトの配列を持つダミーデータを作成しました。

次に、YouTubeUIを作成しましょう。 3つのコンポーネントがあります。

Card 動画のサムネイル、タイトル、視聴回数、公開日、チャンネルの詳細を保持します。
CardList 連続してすべてのカードを返します。
App ダミーデータオブジェクトをマウントし、スケルトンUIを2秒間ロードして、 dummyDataコンポーネントをCardListます。

srcフォルダー内にフォルダーを作成し、 componentsという名前を付けます。 componentsフォルダ内にCard.jsファイルを作成し、それに次のコードを追加します。

 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;

Cardコンポーネントを作成しました。 その中で、 reactからReactをインポートし、 itemchannelの小道具を分解して、 Cardコンポーネント全体で使用できるようにしました。 1つのビデオを表示する各Cardアイテムコンポーネントには、サムネイル、ビュー数、発行日、およびタイトルが表示されます。

CardListコンポーネント

componentsフォルダ内にCardList.jsファイルを作成し、それに次のコードを追加します。

 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;

このコンポーネントでは、作成したCardコンポーネントをインポートしました。 カードは、 list.itemsを介してマッピングすることで取得するitemchannelの小道具を受け入れます。 次に、このコンポーネントをCardListとしてエクスポートします。これは、 Appコンポーネントで使用するためです。

このコンポーネントにマップされるitems配列は、 dummyData内のオブジェクトの配列です。

アプリコンポーネント

src/ディレクトリのapp.jsファイル内にあるコードを削除し、それに以下を追加します。

 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;

このコンポーネントでは、 useStateフックとuseEffectフックを、 Reactと、作成したAppコンポーネントで必要となる他のファイルと一緒にインポートしました。

データはダミーデータであるため、JavaScriptのsetTimeoutメソッドを使用して、2秒のタイムアウト後にコンテンツをロードすることにより、APIデータのようにモックアップする必要があります。

次に、 Appコンポーネントで、ビデオ状態を作成し、 useStateを使用して状態を空の配列に設定します。

ダミーデータをロードするには、 useEffectフックを使用します。 このフックでは、 setTimeout ()関数を保持する可変タイマーを作成します。 関数内で、ビデオの状態をdummyDataオブジェクトに設定し、2秒後にデータが読み込まれるようにします。最後に、マウント解除中にタイマーをキャンセルします。

最後に、ビデオの状態をマッピングし、 list-sectionCardListコンポーネントを含むsection要素とそのリストプロップを返します。

CSSの追加

これまで、実際のCSSなしで多くのクラスを使用してきました。 srcフォルダー内で、 App.css内のすべてを削除し、次のコードに置き換えます。

 .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%; } }

スケルトン画面がない場合のYouTubeUIの外観を見てみましょう。 ページが読み込まれると、2秒間白い画面が表示され、その後データがすぐに読み込まれることがわかります。

スケルトン画面のないYouTubeのようなUI
YouTube-スケルトン画面のないUIのようなもの(大きなプレビュー)

ReactLoadingスケルトンの使用

コンテンツのフォントサイズ、行の高さ、余白に合わせてスケルトン画面を細心の注意を払って作成する他のライブラリとは異なり、 Skeletonコンポーネントは、読み込まれるコンテンツの代わりに、コンポーネントで直接使用されるように設計されています。

React LoadingSkeletonを他のものよりも選んだ理由をいくつか見ていきましょう。

テーマ

React LoadingSkeletonはテーマ設定をサポートしています。 したがって、 SkeletonThemeを使用してすべてのスケルトンコンポーネントの色を簡単に変更し、値をカラーpropsに渡すことができます。

以下は、それがどのように機能するかを示す例です。

 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> 
実行中のテーマ効果
実行中のテーマ効果(大きなプレビュー)

間隔

heightwidthcolor小道具に加えて、 durationの小道具を指定することもできます。

 <Skeleton duration={2} />

期間のデフォルトは1.2です。 これにより、スケルタルアニメーションの1サイクルを実行するのにかかる時間が決まります。

詳細については、ドキュメントをご覧ください。

スケルトンスクリーンUIの実装

次に、 react-loading-skeletonをインストールします。 ターミナルで次のコマンドを実行して、パッケージをインストールします。

 npm install react-loading-skeleton

スケルトンコンポーネント

ビデオデータのスケルトンコンポーネントを作成しましょう。 componentsフォルダ内にSkeletonCard.jsファイルを作成し、次のコードを追加します。

 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;

順序付けられていないリストを作成しました。 その中で、 Array.fill()メソッドを使用しました。 ダミーデータのアイテムが9つあるため、 Array.fill()メソッドを使用してitemsオブジェクトの長さをループし、インデックス値なしで埋めて、配列を空にしました。 動作については、Array.fillのドキュメントを参照してください。

次に、空の配列をマッピングしてスケルトンプロパティを含むリストを返し、各スケルトンプロパティの値を指定しました。

ここで、 heightはスケルトンの長方形の長さを示し、 widthは幅を示し、 circleはスケルトンUIの丸みを帯びた部分を作成します。

React Loading SkeletonにはデフォルトのPulseアニメーションが付属しているため、便利です。 プロジェクトに合わせてPulseアニメーションを作成することもできますが、私に言わせれば、デフォルトのままにしておきます。

最後に、完全なソースコードが利用可能です。

これで、完全に機能するスケルトン画面UIができました。 この例では、コンテンツを表示する前に5秒間スケルトンを表示しています。

これまでの結果を見てみましょう。

YouTubeのようなUIとスケルトン画面のUI
YouTubeのようなスケルトンUI(大プレビュー)

結論

スケルトン画面は、完全に空白の画面に直面することによるフラストレーションを回避し、コンテンツが読み込まれる前にどのように見えるかをユーザーに印象付けることで、ユーザーエクスペリエンスを大幅に向上させます。

これまで見てきたパッケージのいずれかに慣れていない場合は、ページのレイアウトを模倣した長方形や円を作成して、独自のスケルトンUIを作成できます。

以下のコメントセクションでフィードバックと経験を共有してください。 あなたが思いついたものを見てみたいです!

この記事のサポートリポジトリはGithubで入手できます。

参考文献

  • 「スケルトンスクリーンについて知っておくべきことすべて」、Bill Chung、UX Collective
  • 「Reactを使用したスケルトン読み込みページ」、Anthony Panagi、Octopus Wealth
  • 「ReactおよびReactNativeを使用したスケルトンスクリーン」、Chris Dolphin、Alligator.io
  • 「Reactでのスケルトンローディングの実装」、Adrian Bece、DEV