Next.js レンダリング手法まとめ
Next.jsの4つのレンダリング手法について
静的サイト生成(SSG: Static Site Generation)
- ビルド時にAPIを呼び出しデータを取得、ページを描画して静的ファイルとして生成する
- 生成した静的ファイルはビルド結果に保持され、ページアクセス時にはその静的ファイルをクライアントに送る
メリット
- 初期描画が高速(静的ファイルをクライアントに渡すだけ)
- SEOに対して有効
デメリット
- データ取得がビルド時のみで、古いデータが表示される
使い時
- ビルド後に表示内容が変わらないページ
- 初期描画後にデータを取得・表示するページ
クライアントサイドレンダリング(CSR: Client Side Rendering)
- ブラウザ側で初期描画を行う
- Reactアプリっぽい描画方法
メリット
- リアルタイム性が高い
デメリット
- SEOに対して有効ではない
使い時
- リアルタイム性が重要なページ
サーバーサイドレンダリング(SSR: Server Side Rendering)
- ページにアクセスするたびに、サーバー側でgetServerSidePropsが呼び出され、その結果のProps(データ)を元にサーバー側でページの描画を行い、クライアントで表示する
メリット
- 最新のデータでページの初期描画ができる
- SEOに対して有効らしい
デメリット
- アクセスごとにサーバーで処理を行うため、描画時間が長くなる可能性がある
使い時
- 常に最新のデータを表示させたいページ
インクリメンタル静的再生成(ISR: Incremental Static Regeneration)
- SSGのように事前にページを生成しておく
- クライアントへ渡す静的ファイルに有効期限を設定でき、切れていた場合のアクセスに対してはgetStaticPropsを実行・ページ描画をし、サーバーに保存しているページデータを新しくする
メリット
- そこそこ最新のデータを表示しつつ、初期描画が高速
デメリット
- 常に最新のデータというわけではない
Flutter ListでのforEach内での非同期処理
Flutterで複数選択されたオブジェクトをforeachで個々に非同期処理をしたい際にちょっとはまったのでメモ
実際のコード
Future<void> hogeHoge() async { await Future.forEach(this.hogeIdList, (hogeId) async { // 非同期で行いたい処理 await this.hoge(hogeId); }); notifyListeners(); }
参考
読みやすかった技術書
現場で使えるFlutter開発入門
Flutterの開発の進め方がだいたいわかる本でした。GitHubからサンプルのソースコードをダウンロードできます。ダウンロードしたソースコードを実際に動かして進められるので、理解がしやすいです。ソースコードも全体が書籍のほうにも書かれているので、PCを起動しなくても読み進めていけます。Flutterの基本的なアプリ画面の作り方から、開発手法の選定、ローカルDBのSQLiteや、FirebaseFirestoreの利用など、1冊でFlutterでのアプリ開発が学べます。Flutterでは、HTMLでいうところの画面を構成するタグに相当する「ウィジェット」を用いてアプリの画面を作成していきます。この書籍に出てくるウィジェットをFlutterの公式ドキュメントを見ながら、プロパティの値を変更して動作を確認してみると理解が深まるかと思います。
実践Firestore
Googleが提供するFirebaseというサービスのFirestoreについて、包括的に解説してくれている本です。ページ数は少ないですが、Firestoreとは何か?から、データアクセスやセキュリティルール、データモデリング、ユーザー管理まで網羅されています。約2年前に出版されたもので、少し古くはありますが、大まかなことは現在でも変わっていないと思うので、参考にできることは多いと思います。サンプルコードで使用されているJavaScriptSDKのバージョンが少し古く、書き方が変わっているところは少しあるかもしれません。FirebaseのStorageや、Hosting、Functionsについては一切触れていないですが、個人で簡単に作ったアプリからFirestoreにアクセスして直接CRUD処理を行うなどで、とりあえず使ってみたい場合には十分な内容だと思います。
UNIXという考え方
これは今読んでいる本です。140ページほどですが、UNIXというOSを通して、設計思想について解説されています。自分はUNIXについて全く詳しくありませんが、友人に勧められて読んでいます。20年前に発行されたものですが、いろいろな考え方がしっかり言語化されていて、とてもおもしろいです。上の2冊と比べて実際のソースコードや、公式のドキュメントと一緒に読み進めることで理解がより深まるというタイプの本ではないので、隙間時間にさっと読めておすすめです。本のサイズも小さめなので、持ち運べて便利です。
Flutter Widgetまとめ① StatefulWidget
StatefulWidget
- レイアウトやアニメーションを使った場合でも、高速にレンダリングしたい場合に使用する
- 簡単な処理だけを行うウィジェットでStatefulWidgetを使用し、状態管理する場合はシンプルなコードで読みやすい
- 処理が増えてきて、ロジックが肥大化してくると、描画と処理がごちゃごちゃして、どこで何が行われているか分かりづらく、読みづらいコードになる
StatefulWidgetを作成する際に必要なクラスは以下の2つ
- StatefulWidgetを継承したクラス
- Stateを継承したデータクラス
StatefulWidgetを継承したクラス
- createState()でStateを継承したクラスを返す
class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); }
Stateを継承したクラス
- 変数を更新する場合は、setState()を呼び出す
- setStateで変数が更新され、画面が再buildされる
- StatefulWidgetで定義されている変数にアクセスする場合は、widget.変数名
class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } }
main.dart
import 'package:flutter/material.dart'; void main() { runApp(const MyApp()); } class MyApp extends StatelessWidget { const MyApp({Key? key}) : super(key: key); @override Widget build(BuildContext context) { return MaterialApp( title: 'Flutter Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: const MyHomePage(title: 'Flutter Demo Home Page'), ); } } class MyHomePage extends StatefulWidget { const MyHomePage({Key? key, required this.title}) : super(key: key); final String title; @override State<MyHomePage> createState() => _MyHomePageState(); } class _MyHomePageState extends State<MyHomePage> { int _counter = 0; void _incrementCounter() { setState(() { _counter++; }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ const Text( 'You have pushed the button this many times:', ), Text( '$_counter', style: Theme.of(context).textTheme.headline4, ), ], ), ), floatingActionButton: FloatingActionButton( onPressed: _incrementCounter, tooltip: 'Increment', child: const Icon(Icons.add), ), ); } }
Flutter 環境構築
Flutterの環境構築は必要なものが少し多くて、ややこしいのでまとめておこうと思います。 Windows版です。
FlutterSDKのダウンロード
- 公式サイトからダウンロード・解凍します
- ダウンロード後、環境変数にPathを通します
Flutter doctorコマンドの実行
- Flutterのパスを通したフォルダで以下コマンドを実行します
- flutter doctor
- 開発環境構築で不足しているものがわかります

- VisualStudioはデスクトップアプリの開発に必要ですが、今回は省きます
AndroidStudioのインストール
- 公式サイトからダウンロード・インストールをします
Androidライセンスの承認
- 以下コマンドを実行します
- flutter doctor--android-licenses
Androidエミュレーターの作成






- 以下のように表示されれば、エミュレーターの作成は完了です

VisualStudioCodeのダウンロード
- 公式サイトからダウンロードします
拡張機能のインストール
- FlutterとDartをインストールしておきます

プロジェクトの作成
- ctrl + shift + p から Flutter: New Project を選択します

Applicationを選択

ディレクトリを選択して、プロジェクト名を入力します

アプリの実行

- 作成したエミュレーターを選択

- エミュレーターが起動します


Flutter DropdownButtonにFirebaseから取得したjsonのリストを指定する
DropdownButtonの使い方
- Firebaseから取得したオブジェクトの形式
{
name: 'AAA',
order: 1,
folderId: 'id'
}
実際のコード
DropdownButton作成
DropdownButton<String>( value: model.selectFolderId, hint: Text('フォルダ'), icon: const Icon(Icons.arrow_downward), elevation: 16, style: const TextStyle(color: Colors.deepPurple), underline: Container( height: 2, color: Colors.deepPurpleAccent, ), onChanged: (String newValue) { model.setFolderId(newValue); }, items: _getDropdownMenuItemList(this.folderList) )
表示メニューを返す関数
List<DropdownMenuItem<String>> _getDropdownMenuItemList(folderList) { var dropdownList = <DropdownMenuItem<String>>[]; dropdownList .add(new DropdownMenuItem<String>(value: '', child: Text('選択しない'))); if (model.folderList != null && folderList.length > 0) { for (var folder in folderList) { dropdownList.add(new DropdownMenuItem<String>( value: folder.folderId, child: Text(folder.name))); } } return dropdownList.toList(); }
ドロップダウンのリストに表示するのはnameで、選択されたときに格納する値はfolderIdを指定する。
provider側で最新のフォルダリストを取得し、DropdownButtonのitemsにリストを表示する。
DropdownMenuItemを別関数からList<DropdownMenuItem


Flutter theme アプリ共通カラーコード・スタイル設定
- Flutterの共通スタイルはMaterialAppのルートウィジェットにthemeを設定する
- ダークモードにもthemeで対応できる
main.dart
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
theme: createTheme(),
debugShowCheckedModeBanner: false,
home: SignUpPage(),
);
}
}
- themeに設定できるプロパティはけっこう多い themeを返す関数
import 'package:flutter/material.dart'; ThemeData createTheme() { return ThemeData( primarySwatch: Colors.blue, ); }
- colorコード定義
import 'package:flutter/material.dart'; class ThemeColors { static const baseColor = const Color(0xFF222831); static const accentColor = const Color(0xFFFD7013); static const subColor = const Color(0xFF393E46); static const textColor = const Color(0xFFEEEEEE); }