💁

riverpodでFormのValidationを実現したい🤔

2022/08/28に公開

いつもの使い方だと、ドキュメントを参考にできない!

riverpodを使っているTodoアプリで、入力フォームに、Flutter公式のドキュメントを参考に、Validation機能をつけたかったが上手くいかなかった!

Providerを使って、機能を自作しないと出来ないようなので、難しくて挫折したので、riverpodでもStatefulWidgetを使う方法があるので、そちらで試してみると、公式ドキュメントの使い方をそのまま使うことができた!

参考にしたドキュメント
https://docs.flutter.dev/cookbook/forms/validation

私は、hooks_riverpodflutter_hooksを使っているので、こちらをFlutterアプリに追加しました。

https://pub.dev/packages/hooks_riverpod/example
https://pub.dev/packages/flutter_hooks

今回は、こちらのriverpodの日本語翻訳された公式ドキュメントに書かれていた、StatefulHookConsumerWidgetを使用しました。

https://riverpod.dev/ja/docs/concepts/reading/

サンプルコード

公式ドキュメントに書かれていた、コメントが気になったので翻訳して書いている部分もあります。普段見ているコメントには、重要な意味があり、Googleのエンジニアさんは、使ってくれる人のために書いてくれているそうです。親切ですね。普段は全然読んでないけど😅

main.dart
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:form_validator/next_page.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

void main() {
  runApp(
    const ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  
  Widget build(BuildContext context) {
    const appTitle = 'Form Validation Demo';

    return MaterialApp(
      title: appTitle,
      home: Scaffold(
        appBar: AppBar(
          title: const Text(appTitle),
        ),
        body: MyCustomForm(),
      ),
    );
  }
}

class MyCustomForm extends StatefulHookConsumerWidget {
  // コンストラクターは使わないので、消すかコメントアウトする!
  // const MyCustomForm(Key? key) : super(key: key);

  
  MyCustomFormState createState() => MyCustomFormState();
}

class MyCustomFormState extends ConsumerState<MyCustomForm> {
  // Form ウィジェットを一意に識別するグローバルキーを作成します。
  final _formKey = GlobalKey<FormState>();

  
  Widget build(BuildContext context) {
    final instructions = useState('ユーザー情報を入力してください!');

    // 上記で作成した_formKeyを使ってFormウィジェットを作ります。
    return Container(
      child: Center(
        child: Form(
          key: _formKey,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.center,
            children: [
              const SizedBox(height: 20),
              Text(instructions.value,
                  style:
                      const TextStyle(fontSize: 15, color: Colors.redAccent)),
              const SizedBox(height: 20),
              TextFormField(
                // validatorは、ユーザーが入力したテキストを受け取ります。
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'メールアドレスが入力されていません!';
                  }
                  return null;
                },
              ),
              TextFormField(
                // validatorは、ユーザーが入力したテキストを受け取ります。
                validator: (value) {
                  if (value == null || value.isEmpty) {
                    return 'パスワードが入力されていません!';
                  }
                  return null;
                },
              ),
              Padding(
                padding: const EdgeInsets.symmetric(vertical: 16.0),
                child: ElevatedButton(
                  onPressed: () {
                    // Validateは、フォームが有効な場合はtrueを、そうでない場合はfalseを返します。
                    if (_formKey.currentState!.validate()) {
                      Navigator.push(context,
                          MaterialPageRoute(builder: (context) => Nextpage()));

                    } else {
                      // フォームが有効でなければ、スナックバーを表示する。
                      ScaffoldMessenger.of(context).showSnackBar(
                        const SnackBar(content: Text('ユーザ情報の入力をお願いします!')),
                      );
                    }
                  },
                  child: const Text('ログイン'),
                ),
              ),
            ],
          ),
        ),
      ),
    );
  }
}
next_page.dart
import 'package:flutter/material.dart';
import 'package:flutter/src/foundation/key.dart';
import 'package:flutter/src/widgets/framework.dart';

class Nextpage extends StatelessWidget {
  const Nextpage({Key? key}) : super(key: key);

  
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ログイン後のページ'),
      ),
      body: const Text('ようこそ!'),
    );
  }
}

最後に

最近、StatefulWidgeを使わないように、頑張っているのですが必要なときも出てくるので、今回のような方法を使ってドキュメントに書いてある便利な機能をそのまま使って、できるだけ速く実現したい機能を開発したいと思いました😇

Discussion