この記事は「株式会社オープンストリーム "小ネタ" Advent Calendar 2020」の2日目の記事です。
はじめに
フロントエンドフレームワークのVueと比較してTypeScriptが導入しやすいReactで、TypeScriptを前提としたプロジェクトを作成します。
環境
$ node --version
v14.15.0
{
...
"dependencies": {
"next": "10.0.3",
"react": "17.0.1",
"react-dom": "17.0.1"
},
"devDependencies": {
"@types/node": "^14.14.10",
"@types/react": "^17.0.0",
"typescript": "^4.1.2"
}
}
React のプロジェクトを作る
こちらは TypeScript を使うオプションがあるので使っていきましょう。
npx create-react-app --template typescript .
Next.js のプロジェクトを作る
create-react-app のようにプロジェクト立ち上げから TypeScript に対応するテンプレートは用意されていません。
なので、プロジェクトを作った後は自分でTypeScriptの設定を追加します。
npx create-next-app .
次にTypeScriptで使うためのパッケージを導入します。
yarn add --dev typescript @types/node @types/react @types/react-dom
このパッケージを導入しないと yarn dev したときに失敗します。
It looks like you're trying to use TypeScript but do not have the required package(s) installed.
.
Please install @types/node by running:yarn add --dev @types/nodeIf you are not trying to use TypeScript, please remove the tsconfig.json file from your package root (and any TypeScript files in your pages directory).
ページを構成するファイルも jsx から tsx に変更します。
-
./pages/_app.js->./pages/_app.tsx -
./pages/index.js->./pages/index.tsx -
./pages/api/hello.js->./pages/api/hello.ts
APIはtsにする
APIのサンプルには型をつけます。APIを作りこむのはまたの機会にしましょう。
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import { NextApiRequest, NextApiResponse } from "next";
export default (req: NextApiRequest, res: NextApiResponse) => {
res.statusCode = 200
res.json({ name: 'John Doe' })
}
この状態で yarn dev を実行してdevelopment用のサーバーを立ち上げるとTypeScriptを使うようになります。
tsconfig.json は yarn dev を実行したときに自動生成されます。
We detected TypeScript in your project and created a tsconfig.json file for you.
おまけ: Reactのページ(コンポーネント)をNext.jsに移植する
Reactのclassで作ったコンポーネントはをそのまま Next.js の pages に移植すると動作します。
例えば create-react-app で生成されたサンプルもほぼそのまま移植することができますが、
外部ファイルとしてCSSや画像が配置されているので これを解決します。
import React from 'react';
import logo from './logo.svg';
import './App.css';
function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
CSSに関してはtsxに書かれているままの記述でインポートできないため、Nextの _app.tsx に追記します(グローバルで適用されれます)
import '../styles/globals.css'
import '../styles/react.css' // ./src/App.css
function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
export default MyApp
error - ./styles/react.css
Global CSS cannot be imported from files other than your Custom . Please move all global CSS imports to pages/_app.js. Or convert the import to Component-Level CSS (CSS Modules).
Read more: https://err.sh/next.js/css-global
logo.svgは public に移動させます。また、 import logo from './logo.svg'; は使えないので、 img タグの src はWebに公開した時の絶対パスを指定します。
Nextに移植したコンポーネントはこんな感じです。
import React from 'react';
function App() {
return (
<div className="App">
<header className="App-header">
<img src="/logo.svg" className="App-logo" alt="logo" />
<p>
Edit <code>src/App.tsx</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}
export default App;
また、classの形で書いたReactコンポーネントもNext.jsで動作するようです。
例えばこのようなReactコンポーネントも同様にNextのpagesに配置すると動作します。
(簡単なサンプルで試したので、複雑なコンポーネントではうまくいかないかもしれません)
import React, { Component } from 'react';
type Props = { ... }
type State = { ... }
class App extends Component<Props, State> {
constructor(props: Props) {
super(props)
...
}
render() {
return (
...
);
}
}
export default App;
Nuxt.jsの pages にVueのコンポーネントを移植した時と同じような感触ですね!
参考
Reactの環境構築 — 仕事ですぐに使えるTypeScript ドキュメント
https://future-architect.github.io/typescript-guide/react.html#next-js
Next.jsとTypeScriptでアプリを作る - Qiita
https://qiita.com/kojiro_ueda/items/a490f5dfc77f5f89ecbd#2-webapi%E3%82%82%E4%BD%9C%E3%81%A3%E3%81%A6spa%E3%81%8B%E3%82%89%E5%8F%A9%E3%81%91%E3%82%8B%E3%82%88%E3%81%86%E3%81%AB%E3%81%99%E3%82%8B