[Flutter]いいね機能を簡単に実装しよう！

#最も簡単にいいね機能を実装します！
2つの方法を紹介します。お好きな方法で実装してください！
どちらも簡単ですのでご安心を！

__※注意__
・StatefulWidgetでsetState()を使えば簡単に作れるけど、全体がリビルドされるから画像やテキストが多い画面でリビルドされると不具合に繋がったり、処理がグダつくのでStatefulWidgetは使いません。
・SNSの機能としていいね機能を実装する場合は,この記事だけでは不十分です。
なぜなら、いいねしたことを保存しなければならないから、サーバーサイドと組み合わせる必要があるからです。


####1.flutter_hooksを利用した方法
####2.providerを利用した方法


##完成品
<img width="300" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/839966/51a98737-de77-ca05-a9f5-56ae69778a5c.gif">
#準備
パッケージを導入します。

```pubspec.yaml
  hooks_riverpod: ^0.14.0+4
  provider: ^5.0.0
```
準備完了。

#1.flutter_hooksを利用した方法
コードを全部のせます!

```hooks_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';

class HooksPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("flutter_hooksパターン"),
      ),
      body: ListView.builder(
          itemCount: 10,
          itemBuilder: (context, index) {
            return Row(
              mainAxisAlignment: MainAxisAlignment.spaceAround,
              children: [
                Text(
                  index.toString() + "番目",
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    fontSize: 20,
                  ),
                ),
                FavoriteButton()
              ],
            );
          }),
    );
  }
}

class FavoriteButton extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final favorite = useState<bool>(false);
    return IconButton(
      onPressed: () =>
          (favorite.value) ? favorite.value = false : favorite.value = true,
      icon: Icon(
        Icons.favorite,
        color: (favorite.value) ? Colors.pink : Colors.black12,
      ),
    );
  }
}
```
重要な部分だけ抜粋します。

```Dart
class FavoriteButton extends HookWidget {
  @override
  Widget build(BuildContext context) {
    final favorite = useState<bool>(false);
    return IconButton(
      onPressed: () =>
          (favorite.value) ? favorite.value = false : favorite.value = true,
      icon: Icon(
        Icons.favorite,
        color: (favorite.value) ? Colors.pink : Colors.black12,
      ),
    );
  }
}
```
favoriteの値が変更されると,内部のnotifyListeners();が実行されてHookWidgetがリビルドされます。

#2.providerを利用した方法

```provider_page.dart
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class ProviderPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("providerパターン"),
      ),
      body: ListView.builder(
          itemCount: 10,
          itemBuilder: (context, index) {
            return ChangeNotifierProvider<FavoriteModel>(
                create: (_) => FavoriteModel(),
                child: Row(
                  mainAxisAlignment: MainAxisAlignment.spaceAround,
                  children: [
                    Text(
                      index.toString() + "番目",
                      textAlign: TextAlign.center,
                      style: TextStyle(
                        fontSize: 20,
                      ),
                    ),
                    Consumer<FavoriteModel>(builder: (context, model, child) {
                      return IconButton(
                        onPressed: model.changeColor,
                        icon: Icon(
                          Icons.favorite,
                          color: model.favorite ? Colors.pink : Colors.black12,
                        ),
                      );
                    })
                  ],
                ));
          }),
    );
  }
}

class FavoriteModel extends ChangeNotifier {
  bool favorite = false;

  void changeColor() {
    if (favorite) {
      favorite = false;
    } else {
      favorite = true;
    }
    notifyListeners();
  }
}
```
各々のListに対して, FavoriteModel()を生成するので、create: (_) => FavoriteModel(),の位置が重要です。ボタンが押されたら、model.chageColorを呼び出されるので、Consumerで囲った部分がリビルドされます。