質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.49%

state_notifierでのcontext範囲外処理について

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 2,284

score 11

前提・実現したいこと

Flutterのstate_notifierの勉強の為、demoを作成してみたのですが、
app_page.dartのfloatingActionButton部分のように
contextの範囲外(() => {})になってしまう処理はどのように記載すればよろしいのでしょうか?

お手数ではございますが御教唆お願いいたします

発生している問題・エラーメッセージ

Tried to use `context.select` outside of the `build` method of a widget.

Any usage other than inside the `build` method of a widget are not supported.
'package:provider/src/inherited_provider.dart':
Failed assertion: line 215 pos 12: 'widget is LayoutBuilder || debugDoingBuild'

該当のソースコード

1.main.dart

import 'package:checkstatenotifer/app_page.dart';
import 'package:checkstatenotifer/app_state.dart';
import 'package:flutter/material.dart';
import 'package:flutter_state_notifier/flutter_state_notifier.dart';
import 'package:provider/provider.dart';

void main() {
  runApp(
    MultiProvider(
      providers: [
        StateNotifierProvider<AppController, AppState>(
          create: (_) => AppController(),
        ),
      ],
      child: MyApp(),
    ),
  );
}

2.app_state.dart

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:state_notifier/state_notifier.dart';

part 'app_state.freezed.dart';

@freezed
abstract class AppState with _$AppState {
  const factory AppState({
    @Default(0) int counter,
    @Default(false) bool color,
    String text,
  }) = _AppState;
}

class AppController extends StateNotifier<AppState> {
  AppController() : super(const AppState());

  void switchColor(bool value) {
    state = state.copyWith(color: value);
  }

  Color getColor() {
    return state.color ? Colors.red : Colors.blue;
  }

  void setText(String value) {
    state = state.copyWith(text: value);
  }

  void increment() {
    state = state.copyWith(counter: state.counter + 1);
  }
}

3. app_page.dart

import 'package:checkstatenotifer/app_state.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('State_Notifier Demo'),
      ),
      body: Column(
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          Center(
            child: Padding(
              padding: const EdgeInsets.all(10),
              child: Column(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  TextField(
                    enabled: true,
                    maxLength: 30,
                    onChanged:
                        context.select((AppController value) => value.setText),
                    decoration: InputDecoration(
                      hintText: 'please input your name',
                      labelText: 'name',
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(15),
                      ),
                    ),
                  ),
                  SwitchListTile(
                      title: const Text('color switch'),
                      value: context.select((AppState value) => value.color),
                      onChanged: context
                          .select((AppController value) => value.switchColor)),
                  Text(
                    context.select((AppState value) => value.text) ?? '',
                    style: TextStyle(
                        color: context
                            .select((AppController value) => value.getColor())),
                  ),
                  DisplayCounter(),
                ],
              ),
            ),
          ),
        ],
      ),
      floatingActionButton: FloatingActionButton(
//            こちらは OK
        onPressed: context.select((AppController value) => value.increment),
//        onPressed: () => {
////            こちらは NG (error: Any usage other than inside the `build` method of a widget are not supported.)
//          if (context.select((AppState value) => value.counter) < 5)
//            {
//              context.select((AppController value) => value.increment),
//            }
//        },
        child: const Icon(Icons.add, color: Colors.white),
      ),
    );
  }
}

class DisplayCounter extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Text(
      context.select((AppState value) => value.counter).toString(),
      style: Theme.of(context).textTheme.headline4,
    );
  }
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'State_Notifier Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const HomePage(),
    );
  }
}

4. app_state.freezed.dart
ターミナルでflutter packages pub run build_runner buildを実行すると作成されます

5. pubspe.yaml

name: checkstatenotifer
description: check_state_notifier

publish_to: 'none' # Remove this line if you wish to publish to pub.dev

version: 1.0.0+1

environment:
  sdk: ">=2.7.0 <3.0.0"

dependencies:
  flutter:
    sdk: flutter
  freezed_annotation:
  flutter_state_notifier: ^0.4.2
  provider: ^4.1.3

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner:
  freezed:
  pedantic_mono: any

flutter:
  uses-material-design: true

補足情報(FW/ツールのバージョンなど)

Flutter 1.19.0-0.0.pre • channel dev
Dart 2.9.0 (build 2.9.0-5.0.dev 4da5b40fb6)

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

check解決した方法

0

下記のような設定をすることでエラーを回避することができました。

app_page.dart
                 ・
                 ・
  Widget build(BuildContext context) {
    final appState = Provider.of<AppState>(context);
    final appController = Provider.of<AppController>(context);

    return Scaffold(
                 ・
                 ・
      floatingActionButton: FloatingActionButton(
        onPressed: () => {
          if (appState.counter < 100)
            {
              appController.increment(),
            }
        },
        child: const Icon(Icons.add, color: Colors.white),
      ),

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.49%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る