본문 바로가기

Flutter/06 Basic

[Flutter] Basic - BuildContext context

BuildContext 에 대해서 몇가지 느낀점을 정리해보았다.

 

  • 위젯트리에서 현재 위젯의 위치를 알수있는 정보
  • BuildContext는 위젯의 정보를 가짐
  • build 메소드에 의해 전해지는 context는 부모 위젯까지의 정보만 가짐

 

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

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(
        primarySwatch: Colors.blue,
      ),
      home: const MyPage(),
    );
  }
}

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

  @override
  Widget build(BuildContext context) { // 여기서 사용하는 context는 Mypage에 대한것임
    return Scaffold(
      appBar: AppBar(
        title: const Text('SnackBar'),
        centerTitle: true,
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            print('Show me is clicked');
          },
          child: const Text('Show me'),
        ),
      ),
    );
  }
}

 

 

여기서 Scaffold 내부에서 사용하는 context가 누구의 것인지 확인하는 코드를 추가해보자

상식적으로는 Scaffold 내부의 context는 Scaffold 의 것이어야 하는데, 현실은 그렇지 않다.

아래 코드처럼 MyPage 부분을 수정하였다.

 

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SnackBar'),
        centerTitle: true,
      ),
      body: Center(
        child: ElevatedButton(
          onPressed: () {
            print('Show me is clicked');
            Scaffold.of(context) // 이부분을 추가해서 발생하는 오류 메시지 확인
                .showSnackBar(const SnackBar(content: Text('Clicked SnackBar')));
          },
          child: const Text('Show me'),
        ),
      ),
    );
  }
}

 

"Show me" 버튼을 클릭하면 오류가 발생한다.

 

 

오류의 내용 중, "Scaffold.of() called with a context that does not contain a Scaffold." 라는 메시지와 "The context used was: MyPage" 메시지를 주목해보면 Scaffold 내부에서 호출된 스낵바에서 참조하는 Scaffold 는 없으며 사용된 context는 MyPage 의 것임을 알 수 있다.

 

해당 문제를 해결하는 방법은 2가지가 있으며 하나는 Builder를 사용해서 context 를 다시 만드는 방법과 새로운 위젯으로 분리하는 방법이 있다.

 

1. 먼저 Builder 를 사용하는 경우, 새로운 context 를 생성할 수 있다.

 

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SnackBar'),
        centerTitle: true,
      ),
      body: Builder( // Builder 로 감싸는 경우
        builder: (context) {
          return Center(
            child: ElevatedButton(
              onPressed: () {
                print('Show me is clicked');
                Scaffold.of(context)
                    .showSnackBar(const SnackBar(content: Text('Clicked SnackBar')));
              },
              child: const Text('Show me'),
            ),
          );
        }
      ),
    );
  }
}

 

여기에서 위젯트리의 변경사항을 확인해 보면 아래 그림과 같다

 

 

오류없이 "Clicked SnackBar" 문자열 화면 출력

 

2. 새로운 위젯으로 분리하는 방법이 있다.

 

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('SnackBar'),
        centerTitle: true,
      ),
      body: MySnackBar(), // 새로운 위젯을 만들어서 context 를 만드는 효과 생김
    );
  }
}

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

  @override
  Widget build(BuildContext context) {
    return Center(
      child: ElevatedButton(
        onPressed: () {
          print('MySnackBar is clicked');
          Scaffold.of(context)
              .showSnackBar(const SnackBar(content: Text('Clicked MySnackBar')));
        },
        child: const Text('MySnackBar'),
      ),
    );
  }
}

 

오류없이 "Clicked MySnackBar" 문자열 화면 출력

 

이상으로 우리가 무의식적으로 사용하던 context 가 위젯들 사이에서 어떤 역할을 하는지 간단히 알아보았다.

 

 

[참고자료] 코딩셰프 -

[https://www.youtube.com/watch?v=o-HpnWhI70U&list=PLQt_pzi-LLfpcRFhWMywTePfZ2aPapvyl&index=18]