LoginSignup
45
41

More than 3 years have passed since last update.

Next.jsとTypeScriptでアプリを作る

Last updated at Posted at 2019-07-10

はじめに

Next.js 9がリリースされました。
TypeScriptを標準サポートし、ものすごく簡単にアプリが作れるようになったようなので、試してみましたので、お知らせします。

やること

  1. Next.jsでアプリを作ってみる。
  2. WebAPIも作って、アプリから叩けるようにする。

できたこと

herokuにデプロイしたもの
Github

0. セットアップ

セットアップは簡単でした。
以下のようにライブラリをインストールしましょう。

$ npm -s i next react react-dom typescript @types/react @types/react-dom @types/node

package.jsonのscriptにはnext dev, next build, next startを書いておきましょう。
Next.jsは基本的にはサーバーサイドレンダリングのフレームワークです。開発時にはnext devでserve, 本番ではnext buildしてプロダクションビルドした上で、next startすることで、余計なコードが除かれた状態でserveできるようになります。

1. 適当なアプリを作ってみる

まずは、next devコマンドで開発サーバーを立ち上げておきます。

画面を出す

まずは、適当なアプリを作ってみましょう。
基本的にはReactなようなので、Next.js特有のところだけ書いていきます。

ページを用意するには、pagesフォルダを用意します。
ここに、適当なtsxファイルを用意することで、ルーティングができます。
pages/foo.tsxを用意すれば/fooで画面にアクセスできるようになります。すごい。
しかも、これ、サーバーサイドレンダリング(SSR)なんですって。簡単。

/pages/foo.tsx
import { NextPage } from "next";
const Index: NextPage = props => {
  return (
    <h1>Hello world!</h1>
  );
}
// default exportしないといけない
export default Index;

画面を出す前に通信をする

シングルページアプリケーション(SPA)ならクライアントで通信するのですが、SSRではサーバー内で取得した上でレンダリングしたHTMLをクライアントにレスポンスします。

レンダリング前にサーバー側で必要なデータを取得するには以下のようにします。

/pages/bar.tsx
import { NextPage } from "next";
interface Props {
  data: { foo: string };
}
const Index: NextPage<Props> = props => {
  return <div>{props.data.foo}</div>;
}
                     // async必須。
Index.getInitialProps = async () => {
  // axiosとかで通信する
  // SSRなので、fetchは使えません(node-fetch入れればいける)。
  return { data: { foo: "bar" } };
}
export default Index;

getInitialPropsで得られた値はpropsで得られます。

別のページに飛ばしたい

aタグのhrefでいけます。

() => {
  return (<a href="/foo/bar">barに飛ぶ</a>);
}

idとか使って動的ルーティングしたい

例えば、/usersというページがあり、/users/:idという動的なパスを持つページがあるとしましょう。
こんなとき、以下のようなジャンプ元の画面と、
(ファイルパスは/pages/users/index.tsx/pages/users.tsxのどちらかでよいです。)

/pages/users/index.tsx
import Link from "next/link"
const Users = () => {
  // Linkを使って動的ルーティングを実現する。Linkタグの間にはaタグが必要。
  // hrefは、URLのフォーマットを示す。
  // asは実際に飛ばすURLを示す。
  return (
    <ul>
      <li><Link href="/users/[id]" as="/users/0"><a>user1</a></Link></li>
      <li><Link href="/users/[id]" as="/users/1"><a>user2</a></Link></li>
      <li><Link href="/users/[id]" as="/users/2"><a>user3</a></Link></li>
    </ul>
  );
}

以下のような、ジャンプ先の画面を用意します。
ファイル名はほんとに[id].tsxとします。

/pages/users/[id].tsx
import { useRouter } from "next/router";
const User = () => {
  const router = useRouter();
  // ジャンプ元で用意した[id]とquery.idが一致する。
  return <div>userId: {router.query.id}</div>
}

あとから気づいたのですが、ジャンプ元の実装はSPAっぽい挙動になるだけでした。
普通に、aタグ使ってhrefで/users/50とかやっても普通にルーティングされます。

動的ルーティングした結果を元に、SSR前にデータを取りたい

getInitialPropsと動的ルーティングの複合技です。
ジャンプ元のコードは同じです。

/pages/users/[id].tsx
const User = () => {
}
User.getInitialProps = async context => {
  const id = context.query.id; // context.query.idにパスが含まれるので、通信に使うなどしましょう。
}

SPAを作る

普通に、Reactと同じです。
動的ルーティングにはLinkを使いましょう。
useStateuseEffectも使えます。

2. WebAPIも作って、SPAから叩けるようにする

APIを作る場合には/pages/api/というフォルダの下にファイルまたはフォルダを作ります。
なお、実装はexpress.jsmiddlewareに似ている気がしますので、ご存知の方は簡単かもしれません。

/pages/api/users.ts
import { NextApiRequest, NextApiResponse } from "next";
// export defaultが必要
export default (req: NextApiRequest, res: NextApiResponse) => {
  res.setHeader("content-type", "application/json");
  res.status(200);
  res.end(JSON.stringify({ users: [{ name: "foo" }] }));
}

叩く場合は/api/usersGETするなどしましょう。
なお、ざっと調べた限りでは、GET, POSTなどメソッドによって呼び分けてくれたりするわけではなさそうなので、関数内で自力でメソッド判定するのがよいかと思いました。
参考

WebAPIも動的ルーティングする

こちらはそんなに難しくなく、req.queryに入っています。
やはりファイル名が重要です。

/pages/api/users/[id].ts
(req: NextApiRequest) => {
  const id = req.query.id;
}

まとめ

ファイルやフォルダ階層でパスを分けることができるところがわかりやすくてよかったです。
何も考えなくてもSSRできたのも:thumbsup:
今回は無理やりWebAPIも作ってみましたが、基本的にはSSRするので、いらないよなー、と思いました。
覚えるコマンドも三つだし、Herokuにデプロイするならメチャ簡単でした。

以上です。よろしくお願いします。

45
41
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
45
41