Flutter에서 setState 없이 상태 관리하기 - Provider 패턴 도입

문제 상황

회사 프로젝트로 Flutter 앱을 개발하면서 setState만으로 상태를 관리했는데, 화면이 10개를 넘어가자 문제가 생겼다. 하위 위젯에서 상태를 변경하려면 콜백을 5단계씩 내려보내야 했고, 불필요한 위젯까지 리빌드되어 성능 이슈가 발생했다.

Provider 패턴 선택

Redux, BLoC, Provider를 비교했다. Redux는 보일러플레이트가 많았고, BLoC은 러닝커브가 있어서 Provider를 선택했다. Google I/O 2019에서도 권장한 방식이라 신뢰할 수 있었다.

class CounterModel extends ChangeNotifier {
  int _count = 0;
  int get count => _count;

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

적용 방법

먼저 provider 패키지를 추가하고, 앱 최상단에 ChangeNotifierProvider를 배치했다.

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => CounterModel(),
      child: MyApp(),
    ),
  );
}

하위 위젯에서는 Provider.of나 Consumer로 상태에 접근했다. Consumer를 쓰면 필요한 부분만 리빌드되어 성능이 개선됐다.

Consumer<CounterModel>(
  builder: (context, counter, child) {
    return Text('${counter.count}');
  },
)

결과

콜백 지옥에서 벗어났고, 상태 로직을 모델로 분리해 테스트도 쉬워졌다. 다만 MultiProvider로 여러 상태를 관리할 때 중첩이 깊어지는 점은 아쉬웠다. 프로젝트 규모가 더 커지면 BLoC도 고려해볼 예정이다.