[作業メモ]ReorderableListView/Provider状態管理で呼び出すコツ

前回(上記事)では、reorderableListviewを使ったのですが、その時は、
状態管理には、ステートフル・setState()を使用していました。故に、ReorderableListViewを使う場所は、静的(Scaffoldのbodyにそのまま)に呼び出していて、flutter.devのサンプル通り、うまく動きました。
今回は、状態管理に、providerを使いました。そうすると、どうなるかというと、前回使用していたsetState()ではなく、(今回は)別ファイル(provider.dart)にメソッドを定義し、そのメソッドが状態に反映される様に、main.dartで、その準備設定をしておく、その後で、前回表示した様に、ReorderableListViewを(Scaffoldのbodyに)呼び出す、という流れになるわけです。
(bodyにそのまま呼び出すと、provider登録したメソッドを呼び出す場所で、エラー(Instance member ‘recorderItems’ can’t be accessed using static access.(インスタンスメンバーなので、クラス名を使って静的にアクセスすることはできません。))が発生します。)

こうならない為に、ちょっとだけコツがあって、(動的に呼び出さないといけない、という仕様があるので)、結論から言うと、Scaffoldのbodyに呼び出すときは、Consumerのbuilderを使います。
(こうすることで、(Provider パッケージを使用して状態管理を行っているので)事前準備したproviderのインスタンスを、providerから取得して、メソッドを正常に呼び出せる様になります。)

目次 index【閲覧時間3分】 click !!>>

1.エラー発生場所

以下の状態管理設定済みのメソッド(recorderItems、removeItems)を呼び出すところで、エラーが発生しました。

(修正前)エラー発生場所(強調部分):
class TaskList2 extends StatelessWidget {
  const TaskList2({super.key});

  // リストアイテムを生成します
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ReorderableListView Sample'),
      ),
      // ReorderableListView の利用
      body: ReorderableListView(
        // ReorderableListView のヘッダープロパティ の利用
        header: const Text('header'),
        padding: const EdgeInsets.symmetric(
          vertical: 8.0,
          horizontal: 8.0,
        ),
        // リストのキーを設定します(再レンダリングを最適化するため)
        key: const ValueKey('ReorderableListView'),
        // onReorder プロパティ の利用
        onReorder: (int oldIndex, int newIndex) {
          taskProvider2.recorderItems(oldIndex, newIndex);
        },
        // リストアイテムのウィジェットを生成します
        children: taskProvider2.items
        .map<Widget>(
          (item) => ListTile(
            // 各アイテムに一意のキーを設定します
            key: Key('$item'),
            tileColor: item % 2 == 0 ? Colors.blue[200] : null,
            title: Text('Item $item'),
            leading: const Icon(Icons.work),
            trailing: IconButton(
              icon: const Icon(Icons.delete),
              onPressed: () {
                taskProvider2.removeItems(item);
              },
            ),
          ),
        ).toList(),
      ),
    );
  }
}

2.修正箇所

・bodyに設定してあるReorderableListViewを、
  Consumer<’状態管理クラス'(上記では、taskProvider2)>( builder: (context, taskProvider2, child) {
  で囲み、かつ、
  return ReorderableListView の様に、return で戻す。

(修正後)
class TaskList2 extends StatelessWidget {
  const TaskList2({super.key});

  // リストアイテムを生成します
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('ReorderableListView Sample'),
      ),
      // ReorderableListView の利用
      body: Consumer<TaskProvider2>(
        builder:(context, taskProvider2, child){
          return ReorderableListView(
            // ReorderableListView のヘッダープロパティ の利用
            header: const Text('header'),
            padding: const EdgeInsets.symmetric(
              vertical: 8.0,
              horizontal: 8.0,
            ),
            // リストのキーを設定します(再レンダリングを最適化するため)
            key: const ValueKey('ReorderableListView'),
            // onReorder プロパティ の利用
            onReorder: (int oldIndex, int newIndex) {
              taskProvider2.recorderItems(oldIndex, newIndex);
            },
            // リストアイテムのウィジェットを生成します
            children: taskProvider2.items
            .map<Widget>(
              (item) => ListTile(
                // 各アイテムに一意のキーを設定します
                key: Key('$item'),
                tileColor: item % 2 == 0 ? Colors.blue[200] : null,
                title: Text('Item $item'),
                leading: const Icon(Icons.work),
                trailing: IconButton(
                  icon: const Icon(Icons.delete),
                  onPressed: () {
                    taskProvider2.removeItems(item);
                  },
                ),
              )
            )
            .toList(),
          );
        },
      ),
    );
  }
}

3.動作確認

コメントを残す