こんにちは、KOUKIです。
NextJSで画面開発をしています。
今回は、テンプレートの実装を行います。
尚、「React, NextJS and Golang: A Rapid Guide – Advanced」コースを参考にしています。解釈は私が勝手に付けているので、本物をみたい場合は受講をお勧めします!
<目次>
前回
事前準備
ファイル
1 2 3 4 5 |
touch next-checkout/pages/success.tsx touch next-checkout/pages/error.tsx mkdir next-checkout/components touch next-checkout/components/Layout.tsx mv next-checkout/pages/index.tsx next-checkout/pages/[code].tsx |
Checkoutテンプレート
BootstrapのCheckoutテンプレートを使って、テンプレートを作成しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
// pages/[code].tsx import Head from 'next/head export default function Home() { return ( <> <Head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossOrigin="anonymous" /> </Head> <div className="container"> <main> <div className="py-5 text-center"> <h2>Welcome</h2> <p className="lead">has invited you to buy these products!</p> </div> <div className="row g-5"> <div className="col-md-5 col-lg-4 order-md-last"> <h4 className="d-flex justify-content-between align-items-center mb-3"> <span className="text-primary">Products</span> </h4> <ul className="list-group mb-3"> <li className="list-group-item d-flex justify-content-between lh-sm"> <div> <h6 className="my-0">Product name</h6> <small className="text-muted">Brief description</small> </div> <span className="text-muted">$12</span> </li> <li className="list-group-item d-flex justify-content-between"> <span>Total (USD)</span> <strong>$20</strong> </li> </ul> </div> <div className="col-md-7 col-lg-8"> <h4 className="mb-3">Personal Info</h4> <form className="needs-validation" noValidate> <div className="row g-3"> <div className="col-sm-6"> <label htmlFor="firstName" className="form-label">First name</label> <input type="text" className="form-control" id="firstName" placeholder="First Name" required /> </div> <div className="col-sm-6"> <label htmlFor="lastName" className="form-label">Last name</label> <input type="text" className="form-control" id="lastName" placeholder="Last Name" required /> </div> <div className="col-12"> <label htmlFor="email" className="form-label">Email</label> <input type="email" className="form-control" id="email" placeholder="you@example.com" required /> </div> <div className="col-12"> <label htmlFor="address" className="form-label">Address</label> <input type="text" className="form-control" id="address" placeholder="1234 Main St" required /> </div> <div className="col-md-5"> <label htmlFor="country" className="form-label">Country</label> <input className="form-control" id="country" placeholder="Country" /> </div> <div className="col-md-4"> <label htmlFor="city" className="form-label">City</label> <input className="form-control" id="country" placeholder="City" /> </div> <div className="col-md-3"> <label htmlFor="zip" className="form-label">Zip</label> <input type="text" className="form-control" id="zip" placeholder="Zip" /> </div> </div> <hr className="my-4" /> <button className="w-100 btn btn-primary btn-lg" type="submit">Checkout</button> </form> </div> </div> </main> </div> </> ) } |

Layoutテンプレート
先ほど設定したテンプレートのHTMLに全てのページに共通して使いたい要素があるので、Layoutコンポーネントにそれを抜き出しましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// components/Layout.tsx import Head from 'next/head' const Layout = (props) => { return ( <> <Head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossOrigin="anonymous" /> </Head> <div className="container"> {props.children} </div> </> ) } export default Layout |
パラメーターに「props」を設定し、HTMLのdiv要素内で「{props.children}」を宣言しました。
このLayoutタグは、以下のように使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
// pages/index.tsx import Layout from '../components/Layout' export default function Home() { return ( <Layout> <main> <div className="py-5 text-center"> <h2>Welcome</h2> <p className="lead">has invited you to buy these products!</p> </div> <div className="row g-5"> <div className="col-md-5 col-lg-4 order-md-last"> <h4 className="d-flex justify-content-between align-items-center mb-3"> <span className="text-primary">Products</span> </h4> <ul className="list-group mb-3"> <li className="list-group-item d-flex justify-content-between lh-sm"> <div> <h6 className="my-0">Product name</h6> <small className="text-muted">Brief description</small> </div> <span className="text-muted">$12</span> </li> <li className="list-group-item d-flex justify-content-between"> <span>Total (USD)</span> <strong>$20</strong> </li> </ul> </div> <div className="col-md-7 col-lg-8"> <h4 className="mb-3">Personal Info</h4> <form className="needs-validation" noValidate> <div className="row g-3"> <div className="col-sm-6"> <label htmlFor="firstName" className="form-label">First name</label> <input type="text" className="form-control" id="firstName" placeholder="First Name" required /> </div> <div className="col-sm-6"> <label htmlFor="lastName" className="form-label">Last name</label> <input type="text" className="form-control" id="lastName" placeholder="Last Name" required /> </div> <div className="col-12"> <label htmlFor="email" className="form-label">Email</label> <input type="email" className="form-control" id="email" placeholder="you@example.com" required /> </div> <div className="col-12"> <label htmlFor="address" className="form-label">Address</label> <input type="text" className="form-control" id="address" placeholder="1234 Main St" required /> </div> <div className="col-md-5"> <label htmlFor="country" className="form-label">Country</label> <input className="form-control" id="country" placeholder="Country" /> </div> <div className="col-md-4"> <label htmlFor="city" className="form-label">City</label> <input className="form-control" id="country" placeholder="City" /> </div> <div className="col-md-3"> <label htmlFor="zip" className="form-label">Zip</label> <input type="text" className="form-control" id="zip" placeholder="Zip" /> </div> </div> <hr className="my-4" /> <button className="w-100 btn btn-primary btn-lg" type="submit">Checkout</button> </form> </div> </div> </main> </Layout> ) } |
Successページのテンプレート
Checkoutが問題なく完了したらSuccessページを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// pages/success.tsx import Layout from '../components/Layout' const Success = () => { return ( <Layout> <div className="py-5 text-center"> <h2>Success</h2> <p className="lead">Your purchase has been completed!</p> </div> </Layout> ) } export default Success |
少し驚いたのですが、NextJSだとルーティングを設定しなくても画面遷移ができます。
「http://localhost:5000/success」にアクセスしてみてください。

画面遷移ができました!
Errorページのテンプレート
Checkoutに問題があれば、Errorページを表示します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// pages/error.tsx import Layout from '../components/Layout' const Error = () => { return ( <Layout> <div className="py-5 text-center"> <h2>Error</h2> <p className="lead">Couldn't process payment!</p> </div> </Layout> ) } export default Error |
「http://localhost:5000/error」にアクセスしてみましょう。

ルーティングの設定
事前設定で、index.tsxを[code].tsxに変換しました。
理由は、CheckoutのURLが以下のようになる想定だからです。
1 2 |
// http://localhost:5000/<code> http://localhost:5000/Xkjd |
NextJSでは、URLよりこのcodeをqueryから抜き出せます。
1 2 3 4 5 6 7 8 9 10 11 |
// pages/[code].tsx import { useRouter } from 'next/dist/client/router' import Layout from '../components/Layout' export default function Home() { const router = useRouter() const { code } = router.query console.log(code) ... } |
例えば、「http://localhost:5000/Xkjd」にアクセスしてみましょう。

コンソールに、「Xkjd」が表示されましたね。そしてページには[code].tsxのファイルの中身が表示されています。
「const { code } = router.query」のcodeは、[code].tsxのcodeに紐づけられるというわけですね。
次回
次回は、LinkDataの実装を行いましょう。
記事まとめ
参考書籍
ソースコード
ここまで実装したソースコードを下記に記載します。
[code].tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
// pages/[code].tsx import { useRouter } from 'next/dist/client/router' import Layout from '../components/Layout' export default function Home() { const router = useRouter() const { code } = router.query console.log(code) return ( <Layout> <main> <div className="py-5 text-center"> <h2>Welcome</h2> <p className="lead">has invited you to buy these products!</p> </div> <div className="row g-5"> <div className="col-md-5 col-lg-4 order-md-last"> <h4 className="d-flex justify-content-between align-items-center mb-3"> <span className="text-primary">Products</span> </h4> <ul className="list-group mb-3"> <li className="list-group-item d-flex justify-content-between lh-sm"> <div> <h6 className="my-0">Product name</h6> <small className="text-muted">Brief description</small> </div> <span className="text-muted">$12</span> </li> <li className="list-group-item d-flex justify-content-between"> <span>Total (USD)</span> <strong>$20</strong> </li> </ul> </div> <div className="col-md-7 col-lg-8"> <h4 className="mb-3">Personal Info</h4> <form className="needs-validation" noValidate> <div className="row g-3"> <div className="col-sm-6"> <label htmlFor="firstName" className="form-label">First name</label> <input type="text" className="form-control" id="firstName" placeholder="First Name" required /> </div> <div className="col-sm-6"> <label htmlFor="lastName" className="form-label">Last name</label> <input type="text" className="form-control" id="lastName" placeholder="Last Name" required /> </div> <div className="col-12"> <label htmlFor="email" className="form-label">Email</label> <input type="email" className="form-control" id="email" placeholder="you@example.com" required /> </div> <div className="col-12"> <label htmlFor="address" className="form-label">Address</label> <input type="text" className="form-control" id="address" placeholder="1234 Main St" required /> </div> <div className="col-md-5"> <label htmlFor="country" className="form-label">Country</label> <input className="form-control" id="country" placeholder="Country" /> </div> <div className="col-md-4"> <label htmlFor="city" className="form-label">City</label> <input className="form-control" id="country" placeholder="City" /> </div> <div className="col-md-3"> <label htmlFor="zip" className="form-label">Zip</label> <input type="text" className="form-control" id="zip" placeholder="Zip" /> </div> </div> <hr className="my-4" /> <button className="w-100 btn btn-primary btn-lg" type="submit">Checkout</button> </form> </div> </div> </main> </Layout> ) } |
Layout.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// components/Layout.tsx import Head from 'next/head' const Layout = (props) => { return ( <> <Head> <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossOrigin="anonymous" /> </Head> <div className="container"> {props.children} </div> </> ) } export default Layout |
success.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// pages/success.tsx import Layout from '../components/Layout' const Success = () => { return ( <Layout> <div className="py-5 text-center"> <h2>Success</h2> <p className="lead">Your purchase has been completed!</p> </div> </Layout> ) } export default Success |
error.tsx
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
// pages/error.tsx import Layout from '../components/Layout' const Error = () => { return ( <Layout> <div className="py-5 text-center"> <h2>Error</h2> <p className="lead">Couldn't process payment!</p> </div> </Layout> ) } export default Error |
コメントを残す
コメントを投稿するにはログインしてください。