Flutterで"HelloWorld"やってみた

##はじめに
はじめまして。
FlutterによるHelloWorldをやってみたので、どうやったのか書いてみたいと思います。
状態管理は、Flutter_HooksとHooks_Riverpod、StateNotifierを使いました。モデルはfreezedで生成しています。
初心者なので間違っている点はご指摘ください。学びになりますので嬉しいです。
## 開発環境
<dl>
  <dt>OS</dt>
  <dd>macOS Catalina 10.15.7</dd>
</dl>

## パッケージ
```yaml:pubspec.yaml
environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  cupertino_icons: ^0.1.3
  flutter_hooks: ^0.14.0
  hooks_riverpod: ^0.11.0
  freezed_annotation: ^0.11.0+1
  state_notifier: ^0.6.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  freezed: ^0.11.6
  build_runner:
  analyzer: 0.39.5
```
## こんな風になるよ
<img width='200' alt="screen_reco.gif" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/12876/9cb50da5-8055-5d86-cf1f-7b15961060a4.gif">
## コード抜粋
```dart:main.dart
void main() => runApp(ProviderScope(child: MyApp()));
```
まずはviewを切り替えるだけの役割を持った、main.dartです。
Riverpodはプロジェクトのルートで`ProviderScope()`を呼び出すようになっているようです。
***
```dart:hello_model.dart
import ...
// ↓ partを指定
part 'hello_model.freezed.dart';

@freezed
abstract class HelloModel with _$HelloModel {
  factory HelloModel({
    @Default('初めまして') String greeting,
    @Default(0) int count,
  }) = _HelloModel;
}
```
続いて、データだけを持つモデル、そのモデルの状態を更新するコントローラーを作成します。
freezedを使い、immutableなモデルを作ります。
partを指定することで、**.freezed.dartファイルを生成できます。

build_runnerパッケージでコードを生成する必要があるので、ターミナルで`flutter pub run build_runner build`を実行する。この時のエラー対策のために、analyzerパッケージを入れています。
***
```dart:hello_model.dart
class HelloModelController extends StateNotifier<HelloModel> {
  HelloModelController() : super(HelloModel());
  // countによってあいさつを切り替えるメソッド
  hello() {
    state.count.isOdd
        ? state = state.copyWith(greeting: 'hello')
        : state = state.copyWith(greeting: 'こんにちは');
  }
  // countを10以下でインクリメントするメソッド
  increment() {
    state = state.count >= 10
        ? state.copyWith(count: 1)
        : state.copyWith(count: state.count + 1);
  }
```
モデルのコントローラーは、StateNotifierで拡張するので、変数はstateだけ使えます。ここでのstateはHello Modelの状態のことです。(たぶん)
状態の変数を変更することにより、一つの変数(state)で複数の状態(greeting, count)を変更できると認識しています。
***
ここからは、Hello Modelのviewを書いていきます。

```dart:hello_view.dart
final controllerProvider = StateNotifierProvider((_) => HelloModelController());

class HelloView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    // (*) useProviderをHookWidget内のbuildメソッドから呼び出す
    final helloState = useProvider(controllerProvider.state);
    final helloController = useProvider(controllerProvider);

    return Scaffold();
```
まずは、クラスの外でStateNotifierProviderを使い、provider(ここではcontrollerProvider)を作ります。providerはimmutableでなければならないので、finalで指定します。

そして、viewをHookWidgetで拡張します。
HookWidgetのbuildメソッド内に、useProviderメソッドを用いて、providerを使うための変数を書きます。

`helloState` -> greetingを表示するために使います。
`helloController` -> counterを更新するためのコントローラーとして使います。
***

```dart:hello_view.dart
class HelloView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    ...
    return Scaffold(
      body: Center(
        child: Container(...),
          child: Center(
            child: Text(
              helloState.greeting,
            ),
```
Textウィジェットでgreetingを呼び出します。
***

```dart:hello_view.dart
class HelloView extends HookWidget {
  @override
  Widget build(BuildContext context) {
    ...
    return Scaffold(
      body: Center(
        child: Container(...),
          child: Center(
            child: Text(...),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          helloController.hello(); // ①
          helloController.increment(); // ②
        },
        ...
      ),
```
①で表示するあいさつの状態を更新します。
②でカウントの状態を更新します。

以上で各要所の説明は終わりです。

## 全コード

[GitHub: yusuketanabe/Flutter_HelloWorld](https://github.com/yusuketanabe/Flutter_HelloWorld)

ありがとうございました。