Table of Contents
このページのゴール
- Providerの概要と使い方を知る
- Providerを使いユーザー情報を管理する
チャットアプリ全体像
機能一覧
- ✨ メールアドレス・パスワードでログインできる
- ✨ ログアウトできる
- ✨ チャットの投稿一覧を表示できる
- ✨ チャットに投稿できる
- ✨ チャットの投稿を削除できる
イメージ図
❗️ 注意事項 ❗️
プロジェクト・雛形の作成が終わっていない場合は
Firebaseを使ったアプリ概要のページを確認しましょう。
状態管理
状態管理とは
まずは状態管理とは何であるかについて理解していきましょう。
Widgetとはでは、
FlutterはWidgetをツリー状に組み合わせUIを実現することを紹介しましたね。
そして、状態を持ったWidgetでは、
データを元にUIを作る仕組みのことを状態を持つと呼ぶことを紹介しましたね。
Widgetをツリー状に組み合わせUIを実現 | データを元にUIを作る |
---|---|
これらの知識を組み合わせると、
様々なデータを元にアプリのUIを作っているのです。
様々なデータのことをアプリの状態と呼び、
その状態を扱いやすく管理する仕組みのことを状態管理と言うのです。
状態管理を行っていないとデータの扱いが複雑になり、
プログラムを書くのが大変になってしまうでしょう 😨😨😨
Provider
状態を持ったWidgetでも紹介したように、
StatefulWidget
と State
を使えば状態を元にUIを作ることは可能です。
ですが、様々なWidgetが組み合わさったUIになり、
状態が複雑になってしまうと、管理しきれなくなってしまうのです。
そこで、登場するのが provider
です。
これを使うことで複雑な状態も簡単に管理することができるのです。
Providerの使い方
次は、Providerの基本的な使い方を紹介していきます。
Providerで出来ること
では、Providerを使うと具体的には何が出来るのでしょうか?
とてもシンプルで親Widgetから子Widgetにデータを受け渡すことが出来るのです。
データを渡す先は、子Widgetであれば何処でもOKです。
データの受け渡し
Providerの基本的なデータの受け渡し方法を確認していきましょう。
使い方は簡単で、親Widgetと子Widgetでデータの受け渡し用の処理を追加するだけで良いのです。
解説
- 親Widgetで
Provider<T>.value()
を使いデータを渡す - 子Widgetで
Provider.of<T>()
を使いデータを受け取る
ソースコード
// ChangeNotifierを継承すると変更可能なデータを渡せるclass CountData {int count = 0;}class ParentWidget extends StatelessWidget {// 渡すデータfinal data = CountData();@overrideWidget build(BuildContext context) {// Provider<T>() で子Widgetにデータを渡す// ※ 渡すデータの クラス と <T> は揃えましょうreturn Provider<CountData>.value(value: data,child: Container(child: ChildWidget(),),);}}class ChildWidget extends StatelessWidget {@overrideWidget build(BuildContext context) {// Provider.of<T>(context) で親Widgetからデータを受け取る// ※ 受け取るデータの クラス と <T> は揃えましょうfinal CountData data = Provider.of<CountData>(context);return Column(children: <Widget>[// 受け取ったデータを使いUI作成Text('count is ${data.count.toString()}'),],);}}
受け渡すデータを更新する
受け渡すデータを更新する方法も確認していきましょう。
こちらも難しいことはなく、
ChangeNotifier
を継承したデータを ChangeNotifierProvider
を使って渡せば良いのです。
解説
- 受け渡すデータは
ChangeNotifier
を継承しnotifyListeners()
を使って変更を知らせる ChangeNotifierProvider
を使ってデータを渡す
ソースコード
// ChangeNotifierを継承すると変更可能なデータを渡せるclass CountData extends ChangeNotifier {int count = 0;void increment() {count = count + 1;// 値が変更したことを知らせる// >> UIを再構築するnotifyListeners();}}class ParentWidget extends StatelessWidget {// 渡すデータfinal data = CountData();@overrideWidget build(BuildContext context) {// Provider<T>() で子Widgetにデータを渡す// ※ 渡すデータの クラス と <T> は揃えましょうreturn ChangeNotifierProvider<CountData>.value(value: data,child: Container(child: ChildWidget(),),);}}class ChildWidget extends StatelessWidget {@overrideWidget build(BuildContext context) {// Provider.of<T>(context) で親Widgetからデータを受け取る// ※ 受け取るデータの クラス と <T> は揃えましょうfinal CountData data = Provider.of<CountData>(context);return Column(children: <Widget>[// 受け取ったデータを使いUI作成Text('count is ${data.count.toString()}'),RaisedButton(child: Text('Increment'),onPressed: () {// データを更新data.increment();},),],);}}
Providerでユーザー情報を管理する
Providerの仕組みや使い方は理解できたでしょうか 🤔
それでは、Providerを使いチャットアプリのユーザー情報を管理してみましょう 💪
Providerをインストール
Providerをインストールしましょう。
作成したFlutterプロジェクトの pubspec.yaml
を開き、
dependencies
に使用するライブラリを追記します。
# --- 省略 ---dependencies:flutter:sdk: flutter# The following adds the Cupertino Icons font to your application.# Use with the CupertinoIcons class for iOS style icons.cupertino_icons: ^0.1.3firebase_auth: ^0.16.0cloud_firestore: ^0.13.5# *** ここを追記 ***provider: ^4.0.5dev_dependencies:flutter_test:sdk: flutter# --- 省略 ---
VSCodeのFlutterプラグインを使っている場合は、
ファイルを保存すれば pubspec.yaml
を元に自動的にライブラリをインストールしてくれるはずです。
もし、上手くインストールしてくれない場合は、以下のコマンドでもインストールできます。
$ flutter pub get
ユーザー情報を管理する
あと少しです、頑張っていきましょう 💪
Providerを使ってユーザー情報の受け渡しを行いましょう。
lib/main.dart
を以下のように書き換えましょう。
解説
ChangeNotifierProvider<UserState>.value()
を使い変更可能なデータを渡すProvider.of<UserState>()
でデータを受け取る- 引数からユーザー情報を渡す処理が不要になった 🤩
ソースコード
import 'package:cloud_firestore/cloud_firestore.dart';import 'package:firebase_auth/firebase_auth.dart';import 'package:flutter/material.dart';import 'package:provider/provider.dart';/* --- 省略 --- */// 更新可能なデータclass UserState extends ChangeNotifier {FirebaseUser user;void setUser(FirebaseUser newUser) {user = newUser;notifyListeners();}}class ChatApp extends StatelessWidget {// ユーザーの情報を管理するデータfinal UserState userState = UserState();@overrideWidget build(BuildContext context) {// ユーザー情報を渡すreturn ChangeNotifierProvider<UserState>.value(value: userState,child: MaterialApp( /* --- 省略 --- */ ),);}}/* --- 省略 --- */class _LoginPageState extends State<LoginPage> {/* --- 省略 --- */@overrideWidget build(BuildContext context) {// ユーザー情報を受け取るfinal UserState userState = Provider.of<UserState>(context);return Scaffold(body: Center(child: Container(padding: EdgeInsets.all(24),child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[TextFormField( /* --- 省略 --- */ ),TextFormField( /* --- 省略 --- */ ),Container( /* --- 省略 --- */ ),Container(width: double.infinity,// ユーザー登録ボタンchild: RaisedButton(color: Colors.blue,textColor: Colors.white,child: Text('ユーザー登録'),onPressed: () async {try {/* --- 省略 --- */final FirebaseUser user = result.user;// ユーザー情報を更新userState.setUser(user);/* --- 省略 --- */} catch (e) {/* --- 省略 --- */}},),),Container(width: double.infinity,// ログイン登録ボタンchild: OutlineButton(textColor: Colors.blue,child: Text('ログイン'),onPressed: () async {try {/* --- 省略 --- */final FirebaseUser user = result.user;// ユーザー情報を更新userState.setUser(user);/* --- 省略 --- */} catch (e) {/* --- 省略 --- */}},),),],),),),);}}// チャット画面用Widgetclass ChatPage extends StatelessWidget {@overrideWidget build(BuildContext context) {// ユーザー情報を受け取るfinal UserState userState = Provider.of<UserState>(context);final FirebaseUser user = userState.user;return Scaffold( /* --- 省略 --- */ );}}/* --- 省略 --- */class _AddPostPageState extends State<AddPostPage> {/* --- 省略 --- */@overrideWidget build(BuildContext context) {// ユーザー情報を受け取るfinal UserState userState = Provider.of<UserState>(context);final FirebaseUser user = userState.user;return Scaffold(appBar: AppBar( /* --- 省略 --- */ ),body: Center(child: Container(padding: EdgeInsets.all(32),child: Column(mainAxisAlignment: MainAxisAlignment.center,children: <Widget>[// 投稿メッセージ入力TextFormField( /* --- 省略 --- */ ),Container(width: double.infinity,child: RaisedButton(color: Colors.blue,textColor: Colors.white,child: Text('投稿'),onPressed: () async {/* --- 省略 --- */final email = user.email;/* --- 省略 --- */},),)],),),),);}}
チャットアプリ完成
お疲れさまでした。
これでチャットアプリの完成です 🎉🎉🎉
FirebaseやProviderを使った、
少しな複雑なアプリを作り上げることができましたね 👍
本格的なアプリを作る上での大切な要素を知ることができたと思います。
- Authenticationを使ったログイン機能
- Firestoreを使ったデータ管理
- Providerを使った状態管理
この他にも、Googleログイン機能やチャットルーム作成機能を付け足してみてもらえると
更に理解が深まるので、ぜひチャレンジして見て下さい 💪💪💪
ソースコード
全体のソースコードを確認したい時は こちら からどうぞ。
まとめ
- Providerを使うと状態管理ができる
- チャットアプリ完成
- 機能追加にチャレンジしてみると理解が深まる
次回からは、今回作ったチャットアプリをWebアプリとして公開する方法を紹介していきます 💪💪💪