flutter で UI をどう作るかの基礎


こちらはニフティグループアドベントカレンダーの記事です。
昨日は @dev_foods の　[オンラインのAWS GameDayにニフティグループで参加してみました](https://blog.web.nifty.com/engineer/3607)でした。
僕も誘ってもらって参加しましたがもうちょっとAWS慣れしてから参加したほうが学びも多かったなと反省しています。

# 背景
最近ちょっとしたアプリで作りたいものがあって flutter で全然いいじゃんと思って勉強し始めました。
（あと vue も理解したいなって思っているのですが flutter はコンポーネント志向っぽいなって思ったので一石二鳥かなって思ったのもあります）
flutter を知らない人のために簡単に説明すると、
dart 言語 を使って iOS と Android の両方のアプリを作れるというフレームワークで、似た技術というか、似た用途で使う技術としては react native とかがあるのかなと思っています。古くは titanium とか。
めちゃめちゃ厳密に言うと flutter は web も作れるし、最近 windows アプリにも対応したってニュース見たけど詳しくはググってください。

この記事では scaffold, StatefulWidget について整理していきます。

# flutterでの基本的なUIの組み方
api による通信をしてその結果を表示する一覧のUIを作ることを考えるとこんなイメージになります。

```listFromJsonApi.dart
import 'package:flutter/material.dart';
import 'package:myapp/logic/communication/communication.dart';
import 'package:myapp/views/search/jsonResults.dart';
import 'package:myapp/widgets/search/searchbar.dart';

class ResultsList extends StatefulWidget {
  ResultsList({Key key, this.from}) : super(key: key);

  final String from;

  @override
  ResultsListState createState() => ResultsListState();
}

class ResultsListState extends State<ResultsList> {

  Widget build(BuildContext context) {
    var _from = widget.from;

    return Scaffold(
      appBar: SearchBar(),
      body: Center(
        child: FutureBuilder(
          future: CommunicationLogic().getJsonWith(from: _from),
          builder: (BuildContext context, AsyncSnapshot snapshot) {
            if (snapshot.hasData) {
              return JsonResults().createListView(snapshot.data, context);
            } else {
              return Text("通信中です");
            }
          }
        )
      ),
    );
  }
}
```

上のような画面を呼び出すとき、呼び出し元はこんな感じになります。

```
ResultsList(from: 'APIへのクエリ')
```


ここで `SearchBar()` は独自のクラスで　appbar　に検索バーを追加するモジュールです。
`CommunicationLogic()` はAPI通信を担当するロジックで、 `getJsonWith` メソッドで引数から検索した結果をJsonで取得しますが、今回の説明とは関係ないです。

##scaffold
scaffold は画面全体を構成するクラスです。 
scaffoldには名前付き引数で渡せる変数が多く用意されており、このコードの場合は `appBar` と `body` が渡されています。
一般的なマテリアルデザインでのアプリを構成する各モジュールが名前付き引数として網羅されており、適切なモジュールを渡すことで画面が作成されます。
このコードの場合は `appBar` に appBar クラスを継承した `SearchBar` クラスのインスタンスが渡されており、 `body` には api通信が終わったら `ListView` のインスタンスを渡すようなコードが書かれています。

他にも `scaffold` には `drawer`, `floatingActionButton`, `bottomNavigationBar` などのコンストラクタが用意されています。
画面全体をクラスとし、各デフォルトコンポーネントを活用することでマテリアルデザインから逸脱しないレイアウトのアプリであれば簡単にレイアウトを作ることが可能です。

個人的には画面全体をクラスとしていることで基本的な画面作成の手間を減らすことに成功しており、ネイティブの iOS や Android の画面構築よりも簡単だと思います。

## statefulWidget と state
今回のコードでは `statefulWidget` と `state` が定義されています。
statefulWidget は state を管理しており state は　widget の現在の状態を表してるという理解をしています。
個人的には `vue.js`　や `react` などのコンポーネント志向の言語やフレームワークに似ていると思うのですが（不勉強なのであっているかはわからない）、ユーザーのアクションによる状態の変化（変数の変化など）は statefulwidget 
 に管理させ、`state` ではそれらの状態を加味したUIコンポーネントや表示のためのロジックを持つという分離になっています。

今回の場合のように、一般的には statefulWidget から state を実行し、state の中にUIを持つ（状態を持つ）のが基本的なUIの作り方になります。

強制的に状態の状態管理とUIを切り分けることができるので個人的にはコードの分割時に様々なアーキテクチャが採用できそうだなと思っています。


#おまけ: flutter触ってる所感
flutterは簡単なアプリであれば初期の学習コストは少なく作れそうだと思っています。ただ、どうしてもiOSに準拠したUIでのアプリを作りたときなどはそれなりの学習が必要そうです。
また、凝った機能を作ろうとすると各プラットフォームのネイティブのフレームワークの知識が必要らしいので、いきなりflutterで凝ったアプリを作ろうとするとしんどそうです。

簡単なアプリを作るにあたってもネストが深くなりがちかつ適当に作るとめちゃめちゃコード自体がファットになっていくとは感じています。コード分割や採用するアーキテクチャをどうするかが結構悩みのタネでそこら辺の知見は今のところないのですが、Bloc パターンが良さそうと先日アドバイスを貰ったのでもうちょっと調べてみようと思っています。

#終わりに
明日は @bobtzw の記事です。お楽しみに！