GatsbyとTypeScriptを使用して書店のランディングページを作成する方法
著者は、 Diversity in Tech Fund を選択して、 Write forDOnationsプログラムの一環として寄付を受け取りました。
序章
ランディングページは、商品やサービスを宣伝するWebページであり、顧客がサイトに到着したときにランディングする場所を提供します。 企業にとって、それらはオンライン広告やマーケティングメールのリンク先になることがよくあります。 商用ランディングページの主な目標は、訪問者を潜在的なクライアントまたは顧客に変えることです。 このため、ランディングページを作成することは、Web開発者にとって貴重なスキルです。
このチュートリアルでは、次の2つのテクノロジーを使用してランディングページを作成します。
- Gatsby 、静的Webサイトを生成するように設計されたReactベースのフロントエンドフレームワーク。 Gatsbyを使用すると、ランディングページをすばやく生成できます。これは、さまざまなプロジェクトの多数のランディングページを作成するときに役立ちます。
- TypeScript はJavaScriptのスーパーセットであり、ビルド時に静的型と型チェックを導入します。 TypeScriptは、コードが誇張される前にコードの問題を開発者に警告する強力な型付けシステムにより、JavaScriptの最も広く使用されている代替手段の1つになっています。 ランディングページの場合、TypeScriptは、売り込みテキストやサインアップフォームの入力など、動的な値に対して無効に入力されたデータを防ぐのに役立ちます。
このチュートリアルで作成するランディングページの例は、書店を宣伝し、ランディングページの次の一般的なコンポーネントを含みます。
- 書店のヘッダー
- ストアに関連するヒーロー画像
- 機能/サービスのリストを含む売り込み
- ビジネスに関するメーリングリストに読者を追加するために使用できる電子メールサインアップフォーム
サンプルプロジェクトは、チュートリアルが終了するまでに次の画像のようになります。
前提条件
- 開発サーバーを実行してパッケージを操作するには、マシンにNodeとnpmをインストールする必要があります。 このチュートリアルは、Node.jsバージョン14.17.2およびnpm6.14.13でテストされています。 macOSまたはUbuntu20.04にインストールするには、Node.jsをインストールしてmacOSにローカル開発環境を作成する方法またはPPAを使用したインストールセクションの手順に従います。 Ubuntu20.04にNode.jsをインストールするには。
- Gatsby CLIツールがインストールされ、
gatsby-starter-defaultテンプレートから作成された新しいGatsbyサイトが必要になります。 最初のギャツビーウェブサイトの設定方法のステップ1に従って、新しいプロジェクトを開始します。 このチュートリアルでは、このプロジェクトをbookstore-landing-pageと呼びます。 - TypeScriptで動作するようにGatsbyプロジェクトを設定する必要があります。 [X5X] TypeScript を使用してGatsbyプロジェクトをセットアップする方法のステップ1からステップ4に従って、適切な依存関係をインストールし、新しい
tsconfig.jsonファイルを作成します。 TypeScriptでseo.tsxファイルをリファクタリングします。 - GatsbyはReactベースのフレームワークであるため、ReactコンポーネントおよびJSXに精通している必要があります。 このチュートリアルには、formsでのイベントハンドラーの使用も含まれます。 これらの概念などについては、React.jsシリーズのコーディング方法で学ぶことができます。
ステップ1—HeaderおよびLayoutコンポーネントのリファクタリング
このステップでは、前提条件のチュートリアルで作成したbookstore-landing-pageプロジェクトの既存のheader.tsxおよびlayout.tsxコンポーネントをリファクタリングすることから始めます。 これには、デフォルトの型定義をカスタム型インターフェースに置き換え、一部のGraphQLクエリを改訂することが含まれます。 この手順を完了すると、ランディングページのヘッダーにページのタイトルと説明を入力し、将来のコンポーネントを実装するためのレイアウトコンポーネントを作成します。
Header
Headerコンポーネントは、ブラウザウィンドウの上部にページのタイトルと説明を表示します。 ただし、このコンポーネントをリファクタリングする前に、プロジェクトのルートディレクトリにあるgatsby-config.jsファイルを開いて、サイトのメタデータを更新します。 後で、Layoutコンポーネントからgatsby-config.jsを照会して、このデータを取得します。
選択したテキストエディタでgatsby-config.jsを開きます。 エクスポートされたモジュールのsiteMetaDataで、titleとdescriptionの値を、次の強調表示されたコードに示すように、書店の名前とビジネススローガンに変更します。
bookstore-landing-page / gatsby-config.js
module.exports = {
siteMetadata: {
title: `The Page Turner`,
description: `Explore the world through the written word!`,
author: `@gatsbyjs`,
},
plugins: [
...
これらの変更を行った後、gatsby-config.jsファイルを保存して閉じます。
次に、bookstore-landing-page/src/componentsディレクトリ内で、header.tsxファイルを開きます。 ここから、<Header />コンポーネントをリファクタリングして、デフォルトのPropTypesの代わりにTypeScriptタイピングを使用します。 コードに次の変更を加えます。
bookstore-landing-page / src / components / header.tsx
import * as React from "react"
import { Link } from "gatsby"
interface HeaderProps {
siteTitle: string,
description: string
}
const Header = ({ siteTitle, description }: HeaderProps) => (
...
)
export default Header
Header宣言の後にHeader.PropTypesおよびHeader.defaultPropsオブジェクトを削除し、siteTitleを使用して、カスタムタイプのインターフェイスHeaderPropsに置き換えました。およびdescriptionプロパティ。 次に、機能コンポーネントに渡される引数のリストにdescriptionを追加し、それらをHeaderPropsタイプに割り当てました。 新しく定義されたHeaderPropsインターフェースは、<Layout/>コンポーネントのGraphQLクエリから<Header/>コンポーネントに渡される引数のカスタムタイプとして機能します。
次に、<Header />コンポーネントのJSXで、開始headerタグのスタイルを変更して、背景色が青になり、テキストが中央揃えになるようにします。 siteTitleを埋め込まれた<Link/>コンポーネントに保持しますが、descriptionを別の<h3/>タグに追加し、フォントの色を白にします。
bookstore-landing-page / src / components / header.tsx
...
const Header = ({ siteTitle, description }: HeaderProps) => (
<header
style={{
background: `#0069ff`,
textAlign: `center`,
}}
>
<div
style={{
margin: `0 auto`,
maxWidth: 960,
padding: `1.45rem 1.0875rem`,
}}
>
<h1 style={{ margin: 0 }}>
<Link
to="/"
style={{
color: `white`,
textDecoration: `none`,
}}
>
{siteTitle}
</Link>
</h1>
<h3 style={{
color: 'white'
}}>
{description}
</h3>
</div>
</header>
)
export default Header
これで、データがこのコンポーネントに渡されるときにインラインスタイルが設定されます。
変更内容をheader.tsxファイルに保存し、gatsby developを実行して、ブラウザのlocalhost:8000に移動します。 ページは次のようになります。
説明がまだレンダリングされていないことに注意してください。 次のステップでは、これをlayout.tsxのGraphQLクエリに追加して、確実に表示されるようにします。
<Header/>コンポーネントの準備ができたら、ランディングページのデフォルトの<Layout/>コンポーネントをリファクタリングできるようになりました。
Layout
<Layout />コンポーネントはランディングページをラップし、サイトの将来のページのスタイルとフォーマットを共有するのに役立ちます。
このコンポーネントの編集を開始するには、テキストエディタでlayout.tsxを開きます。 ファイルの最後にあるデフォルトのタイプ定義を削除し、importステートメントの後にLayoutPropsという名前の新しいインターフェイスを定義します。 次に、<Layout/>に渡される引数にインターフェイスタイプを割り当てます。
bookstore-landing-page / src / components / layout.tsx
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.com/docs/use-static-query/
*/
import * as React from "react"
import { useStaticQuery, graphql } from "gatsby"
import Header from "./header"
import "./layout.css"
interface LayoutProps {
children: ReactNode
}
const Layout = ({ children }: LayoutProps) => {
...
}
default export Layout
インターフェイスは、ReactライブラリでインポートしたReactNodeタイプを使用します。 このタイプ定義は、ほとんどのReact子コンポーネントに適用されます。これは、<Layout/>がデフォルトでレンダリングするものです。 これにより、<Layout/>のカスタムタイプのインターフェイスを定義できるようになります。
次に、<Layout/>コンポーネント内にあるデフォルトのGraphQLクエリを修正します。 siteMetaDataオブジェクト内に、gatsby-config.jsで設定したdescriptionを追加します。 次に、siteTitleと同様に、フェッチした値を新しいdescription変数に格納します。
bookstore-landing-page / src / components / layout.tsx
...
const Layout = ({ children }: LayoutProps) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
description
}
}
}
`)
const siteTitle = data.site.siteMetadata?.title || `Title`
const description = data.site.siteMetadata?.description || 'Description'
...
これで、descriptionを小道具としてレイアウトの返されたJSXの<Header/>コンポーネントに渡すことができます。 descriptionは、HeaderPropsインターフェイスで必須プロパティとして定義されているため、これは重要です。
bookstore-landing-page / src / components / layout.tsx
...
return (
<>
<Header siteTitle={siteTitle} description={description}/>
...
</>
)
export default Layout
layout.tsxファイルを保存して終了します。
レイアウトの最終的な変更として、layouts.cssに移動し、ページのbodyのすべてのテキストを中央に配置して、スタイルを変更します。
bookstore-landing-page / src / components / layout.css
...
/* Custom Styles */
body {
margin: 0;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
color: hsla(0, 0%, 0%, 0.8);
font-family: georgia, serif;
font-weight: normal;
word-wrap: break-word;
font-kerning: normal;
-moz-font-feature-settings: "kern", "liga", "clig", "calt";
-ms-font-feature-settings: "kern", "liga", "clig", "calt";
-webkit-font-feature-settings: "kern", "liga", "clig", "calt";
font-feature-settings: "kern", "liga", "clig", "calt";
text-align: center;
}
...
layout.cssファイルを保存して閉じ、開発サーバーを起動して、ブラウザーでサイトをレンダリングします。 これで、ヘッダーにレンダリングされたdescription値が見つかります。
Gatsbyサイトのベースファイルをリファクタリングしたので、ページにヒーロー画像を追加して、顧客にとってより視覚的に魅力的なものにすることができます。
ステップ2—ヒーロー画像を追加する
ヒーロー画像は、ランディングページの商品やサービスをサポートするビジュアルです。 このステップでは、書店のランディングページの画像をダウンロードし、gatsby-plugin-imageプラグインの<StaticImage />コンポーネントを使用してサイトにレンダリングします。
注:このプロジェクトはGatsbyバージョン3.9.0を使用しているため、非推奨のgatsby-imageパッケージを使用することはできません。 このパッケージはgatsby-plugin-imageに置き換えられました。 この新しいプラグインは、gatsby-plugin-sharpの助けを借りて、処理機能を備えた応答性の高い画像をレンダリングします。
まず、自由に使用できる画像を提供するサイトUnsplashから本棚の画像をダウンロードします。
curl https://images.unsplash.com/photo-1507842217343-583bb7270b66 -o src/images/bookshelf.png
このコマンドは、curlを使用してイメージをダウンロードします。 -oフラグは、imagesディレクトリ内のbookshelf.pngという名前のファイルに設定した出力を示します。
次に、src/pages/index.tsxファイルを開きます。 Gatsbyのデフォルトのスターターテンプレートにはすでに<StaticImage/>コンポーネントが含まれているため、新しくダウンロードした画像を指すように属性を置き換えます。
bookstore-landing-page / src / pages / index.tsx
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
import Layout from "../components/layout"
import Seo from "../components/seo"
const IndexPage = () => (
<Layout>
<Seo title="Home" />
<StaticImage
src="../images/bookshelf.png"
alt="Bookshelf hero image"
/>
</Layout>
)
export default IndexPage
src属性を追加して、Gatsbyをimagesディレクトリ内の正しい画像に誘導し、次にalt属性を追加して、画像の代替テキストを提供しました。
ファイルを保存して閉じてから、開発サーバーを再起動します。 これで、ダウンロードした本棚の画像が中央にレンダリングされます。
画像がサイトにレンダリングされたら、ページにコンテンツを追加することに進むことができます。
ステップ3—セールスピッチと機能コンポーネントの作成
ランディングページの次の部分では、書店の売り込みを保持する新しいコンポーネントを作成します。 これはあなたの顧客があなたの店に来るべき理由を説明します。
bookstore-landing-page/src/components内で、salesPitchAndFeatures.tsxという名前の新しいファイルを作成します。 新しいファイル内で、Reactをインポートし、SalesPitchAndFeaturesという新しい機能コンポーネントを作成して、エクスポートします。
bookstore-landing-page / src / components / salesPitchAndFeatures.tsx
import * as React from "react"
const SalesPitchAndFeatures = () => {
<>
</>
}
export default SalesPitchAndFeatures
このコンポーネントのインターフェイスには、stringタイプのオプションのsalesPitchプロパティが含まれます。 タイプArray<string>のfeaturesのリストもあります。これは必須です。
bookstore-landing-page / src / components / salesPitchAndFeatures.tsx
import * as React from "react"
interface SalesPitchAndFeaturesProps {
salesPitch?: string
features: Array<string>
}
...
salesPitchとfeaturesのデータは、salesPitchAndFeatures.tsx内にハードコーディングされますが、別の場所(gatsby-config.jsなど)に保存してクエリを実行することもできます。 GraphQLで必要なデータ。 contentオブジェクトのタイプはSalesPitchAndFeaturesPropsになります。
bookstore-landing-page / src / components / salesPitchAndFeatures.tsx
...
interface salesPitchAndFeaturesProps {
salesPitch?: string
features: Array<string>
}
const content: SalesPitchAndFeaturesProps = {
salesPitch: "Come and expand your world at our bookstore! We are always getting new titles for you to see. Everything you need is here at an unbeatable price!",
features: [
"Tens of thousands of books to browse through",
"Engage with the community at a book club meeting",
"From the classics to the newest publications, there's something for everybody!"
]}
const SalesPitchAndFeatures = () => {
return (
<>
...
salesPitchプロップは文字列であり、featuresプロップは文字列の配列であることに注意してください。これは、インターフェイスで設定した場合と同じです。
機能のリストを表示する機能も必要です。 showFeatures(f)関数を作成します。
bookstore-landing-page / src / components / salesPitchAndFeatures.tsx
...
const showFeatures: any = (f: string[]) => {
return f.map(feature => <li>{feature}</li>)
}
const SalesPitchAndFeatures = () => {
return (
<>
...
showFeaturesに渡される引数fは、タイプArray<string>であり、タイプstringの機能の配列と一致しています。 レンダリングされたJSXに変換されたリストを返すには、.map()配列メソッドを使用します。
returnステートメントにコンテンツを入力し、divsでラップして、スタイル設定にクラス名を割り当てます。
bookstore-landing-page / src / components / salesPitchAndFeatures.tsx
...
const SalesPitchAndFeatures = () => {
return (
<div className='features-container'>
<p className='features-info'>
{content.salesPitch}
</p>
<ul className='features-list'>
{showFeatures(content.features)}
</ul>
</div>
)
}
export default SalesPitchAndFeatures
salesPitchAndFeatures.tsxを保存して閉じます。
次に、layout.cssを開いて、<SalesPitchAndFeatures/>コンポーネントで追加されたクラス名にスタイルを追加します。
bookstore-landing-page / src / components / layout.css
...
.features-container {
border: 1px solid indigo;
border-radius: 0.25em;
padding: 2em;
margin: 1em auto;
}
.features-list {
text-align: left;
margin: auto;
}
これにより、売り込みと機能のリストの周囲に境界線が追加され、要素間に間隔が追加されて読みやすくなります。
layout.cssを保存して閉じます。
最後に、このコンポーネントをランディングページにレンダリングします。 src/pages/ディレクトリでindex.tsxを開きます。 <SalesPitchAndFeatures/>コンポーネントをレンダリングされたレイアウトの子に追加します。
bookstore-landing-page / src / pages / index.tsx
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
import Layout from "../components/layout"
import SalesPitchAndFeatures from "../components/salesPitchAndFeatures"
import SEO from "../components/seo"
const IndexPage = () => (
<Layout>
<SEO title="Home" />
<div style={{ maxWidth: `450px`, margin: ' 1em auto'}}>
<StaticImage
src="../images/bookshelf.png"
alt="Bookshelf hero image"
/>
<SalesPitchAndFeatures/>
</div>
</Layout>
)
export default IndexPage
また、divを追加して、画像と売り込みの両方にスタイリングを適用しました。
ファイルを保存して終了します。 開発サーバーを再起動すると、画像の下に売り込みと機能のリストが表示されます。
これで、ランディングページに売り込みがあり、潜在的な顧客になぜ彼らがあなたのビジネスに行くべきかを伝えるのに役立ちます。 次に、ランディングページの最後のコンポーネントであるEメールサインアップフォームを作成します。
ステップ4—サインアップフォームコンポーネントの作成
電子メールサインアップボタンは、ユーザーが電子メールアドレスを入力し、製品またはビジネスに関するその他のニュースや情報にサインアップできるようにする一般的なランディングページコンポーネントです。 これをランディングページに追加すると、ユーザーは顧客になるための実用的なステップを実行できます。
まず、bookstore-landing-page/src/componentsにsignupForm.tsxという名前の新しいファイルを作成します。 このコンポーネントにはカスタムタイプはありませんが、独自の特別なReactベースのタイプを持つイベントハンドラーがあります。
まず、<SignUpForm/>コンポーネントとそのreturnステートメントをビルドします。ヘッダーは次のとおりです。
[label bookstore-landing-page/src/components/signupForm.tsx]
import * as React from "react"
const SignUpForm = () => {
return (
<h3>Sign up for our newsletter!</h3>
)
}
export default SignupForm
次に、マークアップを追加して、onSubmit属性を持つform要素を作成します。この要素は、今のところnullに初期化されています。 間もなくこれにイベントハンドラが含まれますが、今のところ、label、input、およびbuttonタグを使用してフォームの記述を終了します。
bookstore-landing-page / src / components / signupForm.tsx
import * as React from "react"
const SignUpForm = () => {
return (
<React.Fragment>
<h3>Sign up for our newsletter!</h3>
<form onSubmit={null}>
<div style={{display: 'flex'}}>
<input type='email' placeholder='email@here'/>
<button type='submit'>Submit</button>
</div>
</form>
<React.Fragment>
)
}
export default SignupForm
テキストフィールドにメールアドレスを入力し、レンダリングされたランディングページでサインアップをクリックしても、何も起こりません。 これは、フォームが送信されるたびにトリガーされるイベントハンドラーを作成する必要があるためです。 ベストプラクティスは、イベントハンドラーのreturnステートメントの外部に別の関数を作成することです。 この関数には通常、トリガーされたイベントを表す特別なeオブジェクトがあります。
別の関数を作成する前に、関数をインラインで作成して、イベントオブジェクトの静的タイプを把握し、後でそのタイプを使用できるようにします。
bookstore-landing-page / src / components / signupForm.tsx
...
return (
<React.Fragment>
<h3>Sign up for our newsletter!</h3>
<form onSubmit={(e) => null}>
<div style={{display: 'flex'}}>
<input type='email' placeholder='email@here' style={{width: '100%'}}/>
<button type="submit">Submit</button>
</div>
</form>
</React.Fragment>
)
...
}
export default SignupForm
Visual Studio Code のようなテキストエディターを使用している場合、eパラメーターにカーソルを合わせると、TypeScriptの IntelliSense を使用して、予想されるタイプが表示されます。ケースはReact.FormEvent<HTMLFormElement>です。
個別の関数の予想されるタイプがわかったので、次にこれを使用して、handleSubmitと呼ばれる新しい個別の関数を作成します。
bookstore-landing-page / src / components / signupForm.tsx
import * as React from "react"
const SignupForm = () => {
const handleSubmit = (e: React.FormEvent<HTMLFormElement>) => {
e.preventDefault();
alert(alert('The submit button was clicked! You\'re signed up!'))
}
return (
<React.Fragment>
<h3>Sign up for our newsletter!</h3>
<form onSubmit={handleSubmit}>
<div style={{display: 'flex'}}>
<input type='email' placeholder='email@here'/>
<button type='submit'>Submit</button>
</div>
</form>
</React.Fragment>
)
}
export default SignupForm
handleSubmit関数は、フォームが送信されたときにブラウザアラートをトリガーするようになりました。 これは一時的なプレースホルダーであることに注意してください。 ユーザーを実際にメーリングリストに追加するには、これをバックエンドデータベースに接続する必要がありますが、これはこのチュートリアルの範囲を超えています。
signupForm.tsxファイルを保存して閉じます。
次に、index.tsxファイルを開き、新しい<SignupForm/>コンポーネントを追加します。
bookstore-landing-page / src / pages / index.tsx
import * as React from "react"
import { StaticImage } from "gatsby-plugin-image"
import Layout from "../components/layout"
import SalesPitchAndFeatures from "../components/salesPitchAndFeatures"
import SignupForm from "../components/signupForm"
import Seo from "../components/seo"
const IndexPage = () => (
<Layout>
<Seo title="Home" />
<div style={{ maxWidth: `450px`, margin: ' 1em auto'}}>
<HeroImage />
<SalesPitchAndFeatures />
<SignupForm />
</div>
</Layout>
)
export default IndexPage
ファイルを保存して終了します。
開発サーバーを再起動すると、完成したランディングページがブラウザに表示され、電子メールのサインアップボタンが表示されます。
これで、書店のランディングページのすべてのコアコンポーネントの構築が完了しました。
結論
Gatsbyは高速な静的Webサイトを作成し、TypeScriptではデータを静的に入力できるため、ランディングページを作成すると優れたユースケースになります。 その一般的な要素のタイプ(ヘッダー、ヒーロー画像、電子メールのサインアップなど)を形成して、データの形式が正しくないと、本番環境に入る前にエラーが発生するようにすることができます。 Gatsbyは、ページの構造とスタイルの大部分を提供し、その上に構築できるようにします。 この知識を使用して他のランディングページを作成し、他の製品やサービスをより迅速かつ効率的に宣伝できます。
TypeScriptの詳細については、 TypeScriptシリーズでコーディングする方法を確認するか、Gatsby.jsシリーズで静的Webサイトを作成する方法を参照してください。ギャツビーについて。