Never give up

Flutter - context, key example with snackbar, provider 본문

Flutter

Flutter - context, key example with snackbar, provider

대기만성 개발자 2020. 11. 16. 13:18
반응형

context를 사용할때 참조되는 context가 어디인지 확인해야될 때가 있습니다

 

해당 예제에서는 provider를 사용할 때 snackbar를 Scaffold.of(context) 형태로 사용할 때의 문제점

 

그리고 해결방안에 대해 알아보겠습니다

 

Main

class ExamplePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Consumer<ExampleData>(
      builder: (context, items, child) {
        return Scaffold(
          appBar: AppBar(title: Text('Example page')),
          body: Column(
            mainAxisAlignment: MainAxisAlignment.center,
            children: [
              Text(items.getCounter,
                  style: TextStyle(fontSize: 30, fontWeight: FontWeight.bold)),
              Row(
                mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                children: [
                  FlatButton(
                      child: CircleAvatar(child: Text('-')),
                      onPressed: () => items.decrease()),
                  FlatButton(
                      child: CircleAvatar(child: Text('+')),
                      onPressed: () => items.increase())
                ],
              ),
              RaisedButton(
                  child: Text('Show snackbar'),
                  onPressed: () => Scaffold.of(context).showSnackBar(SnackBar(
                      content: Text(
                          'Current counter number is ${items.getCounter}'))))
            ],
          ),
        );
      },
    );
  }
}

 

Data

class ExampleData extends ChangeNotifier {
  int _counter = 0;

  String get getCounter => _counter.toString();

  void increase() {
    _counter++;
    notifyListeners();
  }

  void decrease() {
    _counter--;
    notifyListeners();
  }
}

 

단순한 카운터 예제인데 겉으로 보기에는 문제가 없어보입니다

 

하지만 Scaffold.of(context)에 context를 어디에서 참조하는지 보면

 

consumer builder에 있는 context를 참조하게 되고 그로인해

 

다음과 같은 에러가 발생합니다

 

The following assertion was thrown while handling a gesture:
Scaffold.of() called with a context that does not contain a Scaffold.

No Scaffold ancestor could be found starting from the context that was passed to Scaffold.of(). This usually happens when the context provided is from the same StatefulWidget as that whose build function actually creates the Scaffold widget being sought.

 

Scaffold가 포함되지 않은 context가 Scaffold.of()에 콜되었다 정도로 축약해볼 수 있겠습니다

 

그러면 어떻게 처리를 해줘야될지 고민하게 될텐데

 

해당예제에서 간단하고 확실한 방법은 다음과 같이 Scaffold안에 Consumer를 넣는 방법입니다

Scaffold(
        appBar: AppBar(title: Text('Example page')),
        body: Consumer<ExampleData>(
          builder: (context, items, child) {
            return //이하 생략

 

근데 만약 Scaffold까지 Consumer안에 넣어야되는 상황이 생긴다면 어떻게 할까요

(예를들어 BottomNavi, Drawer, FloatingActionBar 등등을 사용해야될 경우)

 

다른방법이 있겠지만 가장 확실한 방법은 key를 사용하는것입니다

  final _scaffoldKey = GlobalKey<ScaffoldState>();

  @override
  Widget build(BuildContext context) {
    return Consumer<ExampleData>(
      builder: (context, items, child) {
        return Scaffold(
          key: _scaffoldKey,
          
          //다른 위젯부분 중략
          
          RaisedButton(
                  child: Text('Show snackbar'),
                  onPressed: () => _scaffoldKey.currentState.showSnackBar(
                      SnackBar(
                          content: Text(
                              'Current counter number is ${items.getCounter}'))))

 

key가 어떤역할을 하는지 알아보겠습니다

 

공식문서에 따르면 A Key is an identifier for Widgets, Elements and SemanticsNodes.

(key api : api.flutter.dev/flutter/foundation/Key-class.html)

 

Widgets, Elements, SemanticsNodes 를 확인해주는 것 정도로 축약해볼 수 있겠는데요

 

Scaffold안에 key값을 정의해줌으로써 참조를 도와주게 합니다

 

꼭 provider이나 snackbar가 아니어도 context를 참조하는 위젯에서 발생할 수 있는 문제이고

 

에러가 안뜨는데도 제대로 작동 안한다면 context를 어디에서 참조하고 있는지

 

다시한번 확인해 볼 필요가 있을거 같습니다

반응형
Comments