Flutter NoSQL入門

## はじめに

はじめまして！
今年の6月頃からDartとFlutterの勉強をはじめました。

javascriptとJavaの中間みたいな言語があればいいのに...
そんな時に出会ったのがDartでした。
最近も時間がある時はDartの勉強などをしてます！

今回は
DartのフレームワークであるFlutterで使えるNoSQLについて、備忘録も兼ねて書きます。

NoSQLをサクッと使ってみたいという方向けの内容になります。

## 環境

MacOS Catalina
version 10.15.0

```bash
$ flutter --version
Flutter 1.25.0-8.1.pre • channel beta • https://github.com/flutter/flutter.git
Framework • revision 8f89f6505b (29 hours ago) • 2020-12-15 15:07:52 -0800
Engine • revision 92ae191c17
Tools • Dart 2.12.0 (build 2.12.0-133.2.beta)
```

```yaml:pubspec.yaml
environment:
  sdk: ">=2.7.0 <3.0.0"
```

## 下準備

```bash
$ flutter create sample
$ cd sample
```

[Hive](https://pub.dev/packages/hive)というパッケージを`pubspec.yaml`に追加する

```yaml:pubspec.yaml
dependencies:
  flutter:
    sdk: flutter

  # 以下の部分を追加する
  hive: ^1.4.4+1
  hive_flutter: ^0.3.1
```

tarminalにて

```bash
$ flutter pub get
```

を実行

## 使用するコード

`lib/main.dart`は以下を使います。

```dart:main.dart
import 'package:flutter/material.dart';

void main() {
  // アプリ起動
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text("Demo"),
            ),
            body: AppContent()));
  }
}

class AppContent extends StatefulWidget {
  @override
  _AppContentState createState() => _AppContentState();
}

class _AppContentState extends State<AppContent> {
  String _value = 'value';

  void _onChanged(String value) {
    setState(() {
      _value = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.all(16.0), // 周りのスペースを開ける
        child: Column(
          children: [
            Text(_value),
            TextFormField(
              decoration: const InputDecoration(
                border: OutlineInputBorder(), // 外枠付きデザイン
                labelText: "value",
                hintText: 'plese input value',
              ),
              onChanged: _onChanged,
            ),
          ],
        ));
  }
}
```

## 実装開始！

### import

Hiveをflutterで利用するには以下の2つの`import`が必要です。

vscodeでは候補に出てこなくて大変だった...

```dart
import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';
```

### Hiveの初期化など

Hiveは利用前に初期化が必要なので呼び出しましょう！

また、`await`も利用するので`main`関数の戻り値を`Future<void>`にして`async`をつけます。

注）今回はサクッとなので、BDの変数(box)はトップにおいています。

```dart
Box<String> box;

Future<void> main() async {
  // Hiveの初期化
  await Hive.initFlutter();
  // DBに接続
  box = await Hive.openBox<String>('database');
  // アプリ起動
  runApp(MyApp());
}
```

### Hiveの利用

では、Hiveを利用して値を保存していきます。

`_AppContentState`クラスを以下のように変更してください。

```dart
class _AppContentState extends State<AppContent> {
  String _value = box.get('key') ?? 'no value';

  void _onChanged(String value) async {
    if (value == 'delete') {
      await box.delete('key');
    } else {
      box.put('key', '${DateTime.now().toString()}に登録 [$_value]');
    }
    setState(() {
      _value = value;
    });
  }
  ...(略
```

`put(key, value)`で値の保存ができ、
`delete(key, value)`でキーに紐づく値を削除することができます。

## 動かしてみる

`flutter run`を実行すると

```bash
$ flutter run
Running "flutter pub get" in sample...                           2,124ms
Launching lib/main.dart on Chrome in debug mode...
Waiting for connection from debug service on Chrome...             43.7s
Debug service listening on ws://127.0.0.1:59389/7641k7JbRGc=/ws

Running with unsound null safety
For more information see https://dart.dev/null-safety/unsound-null-safety

Warning: Flutter's support for web development is not stable yet and hasn't
been thoroughly tested in production environments.
For more information see https://flutter.dev/web

🔥  To hot restart changes while running, press "r" or "R".
For a more detailed help message, press "h". To quit, press "q".

```
...となり
![Screen Shot 2020-12-17 at 15.05.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630300/b0f78816-e9a4-22e1-a8d0-dd6be44dd9cd.png)
写真のように実行できると思います。

それでは試しに「あああ」と打ち、
terminalに`r`と打ちましょう（ホットリロード）

すると
![Screen Shot 2020-12-17 at 15.33.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/630300/eef45d36-0c76-3da4-2c66-ec037bcea177.png)

このように登録できていることが分かります。

また、「delete」と打ちこみ、リロードすると「no value」に戻ります。

## 完成コード

```dart:main.dart
import 'package:flutter/material.dart';

import 'package:hive/hive.dart';
import 'package:hive_flutter/hive_flutter.dart';

Box<String> box;

Future<void> main() async {
  await Hive.initFlutter();
  box = await Hive.openBox<String>('database');
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
        home: Scaffold(
            appBar: AppBar(
              title: Text("Demo"),
            ),
            body: AppContent()));
  }
}

class AppContent extends StatefulWidget {
  @override
  _AppContentState createState() => _AppContentState();
}

class _AppContentState extends State<AppContent> {
  String _value = box.get('key') ?? 'no value';

  void _onChanged(String value) async {
    if (value == 'delete') {
      await box.delete('key');
    } else {
      box.put('key', '${DateTime.now().toString()}に登録 [$_value]');
    }
    setState(() {
      _value = value;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Container(
        padding: EdgeInsets.all(16.0), // 周りのスペースを開ける
        child: Column(
          children: [
            Text(_value),
            TextFormField(
              decoration: const InputDecoration(
                border: OutlineInputBorder(), // 外枠付きデザイン
                labelText: "value",
                hintText: 'plese input value',
              ),
              onChanged: _onChanged,
            ),
          ],
        ));
  }
}
```

## 最後に

初めてのQiita記事でしたがなんとか書き上げることができました。。。
アウトプットは大切なのですが、まとめて簡潔に書くのは大変なんだと身に染みました。

今回はサクッと試せるようにコード多めで書いてみたつもりです。
サクッとなので詳しくは以下の公式サイトを参照してください。

* https://pub.dev/packages/hive
* https://docs.hivedb.dev/#/

`adoptor`と`generator`を利用してクラスを格納することなんかもできます。

ぜひ使い倒してみてください！