kokogento
@kokogento (ここ げんと)

Are you sure you want to delete the question?

If your question is resolved, you may close it.

Leaving a resolved question undeleted may help others!

We hope you find it useful!

Flutter Providerを使ってForm入力された値を保持したい

現象

環境と概要

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  provider: ^4.3.3

Firebaseを使っていますが、あまり関係がなさそうなのでこの投稿内容では割愛します!

アプリの内容は、好きな映画をコメントと一緒に保存できる、という物です。
今回問題になっているのは「コメントの追加、編集、削除」です。
ToDoリストのようなものを想像していただけると良いかと。。

ソースの構造

lib/
 ├ main.dart
 ├ models
 ├    └ mypage_movie_model.dart // データ構造
 ├ providers
 │ └ mypage_movie_provider.dart // prodiverの処理
 ├ widgets
   ├ save_movie_text.dart // 保存ボタン
   └ mypage_movie_form.dart // Formの部分

現象の詳細

実現したいこと

mypage_movie_form.dartで値を入力

mypage_movie_provider.dartで定義しているpoint1Textに、①で入力された内容が入る

save_movie_text.dartの保存ボタンを押したときに、point1Textが保存される

現状の問題

mypage_movie_form.dartで値を入力

mypage_movie_provider.dartで定義しているpoint1Textに、①で入力された内容が入る

save_movie_text.dartの保存ボタンを押したときに、point1Textが空っぽになっている

該当のソース

main.dart

main.dart
class Home extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MultiProvider(
      providers: [
        ChangeNotifierProvider(
          create: (context) => MyPageMovieProvider(),
        ),
      ],
      child: MaterialApp(
      // 省略

mypage_movie_model.dart

mypage_movie_model.dart
import 'package:cloud_firestore/cloud_firestore.dart';

class MyPageMovieModel {
  MyPageMovieModel(DocumentSnapshot doc) {
    movieId = doc.id;
    title = doc.data()['title'];
    pointText1 = doc.data()['point1'];
  }
  String movieId;
  String title;
  String pointText1;
}

mypage_movie_provider.dart

mypage_movie_provider.dart
import '../models/mypage_movie_model.dart';

class MyPageMovieProvider with ChangeNotifier {
  MyPageMovieModel myPageMovie;
  String point1Text = '';
  final uid = FirebaseAuth.instance.currentUser.uid;
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

  Future fetchMyMovies(int movieId) async {
    final docs =
        await _firestore.doc('users/${uid}/movies/${movieId.toString()}').get();
    this.myPageMovie = MyPageMovieModel(docs);
    notifyListeners();
  }

  Future editMyMovies(int movieId, String title) async {
    final movieRef =
        _firestore.doc('users/${uid}/movies/${movieId.toString()}');
    await movieRef.update({
      'id': movieId,
      'title': title,
      'point1': point1Text, // point1Textが空っぽなので何も保存されない
    });
  } 
}

save_movie_text.dart

save_movie_text.dart
import 'mypage_movie_form.dart';
import '../../providers/mypage_movie_provider.dart';

class SaveMovieText extends StatelessWidget {
  final int id;
  final String title;
  SaveMovieText(this.id, this.title);

  @override
  Widget build(BuildContext context) {
    return Consumer<MyPageMovieProvider>(builder: (context, model, child) {
      return FloatingActionButton(
        onPressed: () async {
          print('保存' + id.toString());
          await model.editMyMovies(id, title);
          print(model.point1Text); // 空っぽ
        },
      );
    });
  }
}

mypage_movie_form.dart

mypage_movie_form.dart
import '../../providers/mypage_movie_provider.dart';

class MyPageMovieForm extends StatelessWidget {
  final int id;
  MyPageMovieForm(this.id);

  final formKey = GlobalKey<FormState>();

@override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider<MyPageMovieProvider>.value(
      value: MyPageMovieProvider()..fetchMyMovies(id),
      child: Consumer<MyPageMovieProvider>(
        builder: (context, model, child) {
          final movie = model.myPageMovie;
          return movie == null
              ? Center(child: CircularProgressIndicator())
              : Form(
            key: formKey,
            child: ListView(
              // 省略
                    Expanded(
                      child: TextFormField(
                        controller: TextEditingController(
                          text:
                              movie.pointText1 != null ? movie.pointText1 : '',
                        ),
                        decoration: InputDecoration(labelText: '見所1'),
                        onChanged: (value) {
                          model.point1Text = value;
                          print(model.point1Text); // ここでは値が入ってる!!!
                        },
                      ),
                    ),
                  ],
                ),
              ],
            ),
          );
        },
      ),
    );
  }
}

想定される原因

ChangeNotifierProviderが原因?

もしmypage_movie_form.dartChangeNotifierProviderを使わなかった場合、save_movie_text.dartmodel.point1Textにしっかり値が入っています。

mypage_movie_form.dart
 @override
  Widget build(BuildContext context) {
    return Consumer<MyPageMovieProvider>(builder: (context, model, child) {
      return Form(
        key: formKey,
        // 省略
         onChanged: (value) {
                          model.point1Text = value;
                          print(model.point1Text);
                        },
save_movie_text.dart
class SaveMovieText extends StatelessWidget {
  final int id;
  final String title;
  SaveMovieText(this.id, this.title);

  @override
  Widget build(BuildContext context) {
    return Consumer<MyPageMovieProvider>(builder: (context, model, child) {
      return FloatingActionButton(
        onPressed: () async {
          await model.editMyMovies(id, title);
          print(model.point1Text); // 値が入ってる

なぜmypage_movie_form.dartChangeNotifierProviderを使っているかというと、もしコメントが保存されていたら、その内容を入力欄にデフォルトで表示したいからです。
そしてコメントを取得するにはmovie idが必要なので、mypage_movie_form.dartChangeNotifierProviderを使っています。

他にいい方法があれば教えてください!!!

試したこと

mypage_movie_provider.dartで定義されているpoint1Textに初期値を入れてみました。

mypage_movie_provider.dart
import '../models/mypage_movie_model.dart';

class MyPageMovieProvider with ChangeNotifier {
  MyPageMovieModel myPageMovie;
  String point1Text = 'テストです'; // ここに値を入れてみる
  final uid = FirebaseAuth.instance.currentUser.uid;
  final FirebaseFirestore _firestore = FirebaseFirestore.instance;

}

しかし、保存ボタンを押したときmodel.point1Textは空っぽでした!!!

save_movie_text.dart
class SaveMovieText extends StatelessWidget {

  @override
  Widget build(BuildContext context) {
    return Consumer<MyPageMovieProvider>(builder: (context, model, child) {
      return FloatingActionButton(
        onPressed: () async {
          await model.editMyMovies(id, title);
          print(model.point1Text); // 「テストです」が表示されず空っぽ
        },
      );
    });
  }
}

最後に

Providerが難しくてあまり理解できていません。。どなたかご教授いただけると幸いです!

関連記事

0

1Answer

mypage_movie_form.dart
 @override
  Widget build(BuildContext context) {
    return Consumer<MyPageMovieProvider>(builder: (context, model, child) {
      model.fetchMyMovies(id);
      final movie = model.myPageMovie;

みたいに、ChangeNotifierProviderを使わずにデータを取得できたので一旦は解決しました。。。。

0Like

Your answer might help someone💌