티스토리 뷰

현재 프로젝트에서 플러터의 상태 관리를 위해서 ChangeNotifierProvider를 사용하고 있다. 

 

ChangeNotifierProvider는 ChangeNotifier로 구현한 클래스에서 notifyListeners()가 호출되면 Provider.of로 구현 클래스를 리스닝하는 위젯을 자동으로 리빌드 해주는 기능이 있다.

 

하지만 프로젝트를 진행하다 보니 리빌드가 너무 많이 발생하는 문제가 발생했다. 왜 그럴까 열심히 알아본 결과, 내가 Provider.of에 대해 제대로 알고 있지 않아서였다.

 

다음 간단한 예제코드가 있다. 참고로 코드가 길어서 필요한 코드가 포함시켰다.

 

SuperWidget의 하위에는 다양한 위젯이 있고, 그중에 SubWidget1도 포함되어 있다. 만일 다른 하위 위젯에서 Provider.of<Conter>(context).increment()가 호출되었다고 하자. 그러면 SubWidget1은 리빌드가 될까?

class Counter extends ChangeNotifier {
  int num = 0;

  void increment() {
    ++num;
    notifyListeners();
  }
}

void main() {
  runApp(MaterialApp(
    home: MultiProvider(
      providers: [
        ChangeNotifierProvider<Counter>.value(value: Counter()),
      ],
      child: SuperWidget(),
    ),
  ));
}

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

  @override
  Widget build(BuildContext context) {
    Provider.of<Counter>(context);  // 여기를 주목하라!
    return const Text("Sub Widget 1");
  }
}

 

나는 처음에 Provider.of<Counter>(context)처럼 코드를 작성하면 리빌드가 되지 않을 줄 알았다. 하지만 Provider.of<Counter>(context)는 Counter 상태를 리턴하기 때문에 SubWidget1은 Counter 상태 변화를 리스닝하게 된다. 그래서 SubWidget1은 Counter 상태가 변경되면 리빌드 하게 된다. (이 사실을 몰라서 내 코드는 뒤죽박죽으로 동작하게 되었다.)

 

Counter 상태만 접근하고 리빌드를 원하지 않는다면 Provider.of()의 listen을 false로 설정하면 된다. listen을 false로 하면 상태 변경을 리스닝하지 않기 때문이다.

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

  @override
  Widget build(BuildContext context) {
    print("Sub Widget 1 build");
    Provider.of<Counter>(context, listen: false);
    return const Text("Sub Widget 1");
  }
}
댓글
공지사항