TypeScriptを使用したNext.js 5からNext.js 6へ移行した時行った対応について

Next.jsReactReduxTypeScript
TypeScriptを使用したNext.js 5からNext.js 6へ移行した時行った対応について
Article
この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Next.jsはこのサイトでも使っているのですが
比較的容易にBFF(バックエンドフォーフロントエンド)が実現できるツールとして大変有用です。

UXを実現していくためにSPA(シングルーページアプリケーション)という
アーキテクトがあげられますが

単純なSPAとしての問題点であげられるのが

  • リクエストの複雑化によるランドトリップ
  • 初回ロード時間の遅延

このあたりの課題の解決としてBFFというアーキテクチャの設計思想があります。

そのためこれらの解決を実現していくために
このサイトではNext.js を採用しました。

そんなNext.js6が5月にリリースされたため
マイグレーションのログとして内容をまとめました。

環境

  • React 16.3.2
  • Next.js 5.1
  • typescript 2.8.3
terminal
$ yarn upgrade --latest next next-redux-wrapper typescript
terminal
$ yarn upgrade --latest @zeit/next-typescript @types/next

packageのバージョン

next-redux-wrapper関連

アップデート後に出たエラー

terminal
__WEBPACK_IMPORTED_MODULE_2_next_redux_wrapper__ is not a function

解決方法

書き方が変わりました。

next-redux-wrapper1系

getInitialPropsを呼び出したReactクラスをwithRedux でラップすることで
ステートを子コンポーネントで参照できます。

/pages/index.tsx
import * as React from 'React'; import { createStore } from 'redux'; import * as withRedux from 'next-redux-wrapper'; import Page from './components/page'; const reducer = (state = {hoge: ''}, action) => { switch (action.type) { case 'HOGE': return {...state, hoge: action.payload}; default: return state } }; const makeStore = (initialState, options) => { return createStore(reducer, initialState); }; class App extends React.Component<object> { public static getInitialProps({ store }: Context): void{ const state = store.getState(); await store.dispatch({type: 'Hoge', payload: 'hoge'}); } public render(): JSX.Element { return ( <Page /> ); } } export default withRedux(makeStore)(App);

受け取った propsを出力

/components/page.tsx
import * as React from 'React'; const Page = (props) => { return <div>Prop from Redux {props.hoge}</div> } export default connect()(Page);

next-redux-wrapper2系

getInitialPropsを呼び出しreact-reduxに渡しProviderします
そのReactクラスをwithRedux でラップすることで
ステートを子コンポーネントで参照できます。

/pages/_app.tsx
import * as React from 'react'; import { createStore } from 'redux'; import { Provider } from 'react-redux'; import App, { Container } from 'next/app'; import withRedux from 'next-redux-wrapper'; const reducer = (state = { foo: '' }, action) => { switch (action.type) { case 'FOO': return { ...state, foo: action.payload }; default: return state } }; const makeStore = (initialState, options) => { return createStore(reducer, initialState); }; class MyApp extends App<object> { static getInitialProps({ Component, ctx }) { const pageProps = Component.getInitialProps ? await Component.getInitialProps(ctx) : {}; return { pageProps }; } render() { const { Component, pageProps, store } = this.props; return ( <Container> <Provider store={store}> <Component {...pageProps} /> </Provider> </Container> ); } } export default withRedux(makeStore)(MyApp);

単純に withRedux の箇所を _app.tsx に切り出す形になりましたが
pagesがかなりシンプルになりました

各ページごとにストアへ保存するデータを分けてかくケースについては
以前よりかなりスッキリ見やすくなっています。

/components/page.tsx
import * as React from 'React'; import Page from './components/page'; class MyApp extends React.Component<object> { public static getInitialProps({ store }: Context):void{ const state = store.getState(); store.dispatch({type: 'Hoge', payload: 'hoge'}); } public render(): JSX.Element { return ( <Page /> ); } } export default App;

コネクト関数については以前と同じ形で使用できます。

/pages/index.tsx
import * as React from 'React'; const Page = (props: object) => { return <div>Prop from Redux {props.hoge}</div> } export default connect()(Page);

@zeit/next-typescript関連

アップデート後に出たエラー

typescriptLoaderOptionsはサポートされなくなりました

terminal
Error: `typescriptLoaderOptions` in next.config.js is no longer supported. https://err.sh/next-plugins/typescript-loader-options

解決方法

以下を削除

next.config.js
typescriptLoaderOptions: { transpileOnly: false }

'next / babel'モジュールを見つけることができません

terminal
UnhandledPromiseRejectionWarning: Error: Cannot find module 'next/babel' from '/Users/XXXX/XXXX'

解決方法

.babelrcを作成し下記を記述

babelrc
{ "presets": [ "next/babel", "@zeit/next-typescript/babel" ] }

終わりに

最後までご覧いただきありがとうございます。
この記事ではTypeScriptを使用したNext.js 5からNext.js 6へ移行した時行った対応についてについて紹介させていただきました。

これからも皆様の開発に役立つ情報を提供していきたいと考えています。
今後ともよろしくお願いいたします。