티스토리 뷰

플러터에서 ChangeNotifierProvider를 이용해서 코드를 작성하는 중에 아래와 같은 에러가 발생했다.

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

  @override
  Widget build(BuildContext context) {
    print("Sub Widget 2 build");
    return ElevatedButton(
      onPressed: () {
        Provider.of<Counter>(context).increment();
      },
      child: const Text("Sub Widget 2"),
    );
  }
}
======== Exception caught by gesture ===============================================================
The following assertion was thrown while handling a gesture:
Tried to listen to a value exposed with provider, from outside of the widget tree.

This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.

To fix, write:
Provider.of<Counter>(context, listen: false);

It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.

The context used was: SubWidget2
'package:provider/src/provider.dart':
Failed assertion: line 274 pos 7: 'context.owner!.debugBuilding ||
          listen == false ||
          debugIsInInheritedProviderUpdate'

 

 

에러 내용은 제스처 처리 중에 위젯 트리 외부에서 Provider로 노출된 값을 들으려고 시도했기 때문이라고 한다. 그리고 해결 방법으로  Provider.of에 listen: false를 사용하라고 한다.

 

그러면 listen 매개변수는 무엇을 의미하는 걸까?

 

listen 매개변수는 해당 상태의 변경 사항을 리스닝할지 여부를 결정하는 데 사용된다.

listen의 기본값은 true이다. true이면 Provider.of는 상태 변경 사항을 구독하고, 해당 상태가 변경될 때마다 위젯이 리빌드 된다. 반면에 false로 설정하면 Provider.of는 상태를 리스닝하지 않게 되고, 단순히 해당 상태의 값을 얻거나 메서드를 호출하게 된다. 따라서 위젯이 불필요하게 리빌드 되지 않으며, 앱의 성능을 높일 수 있다.

 

결국, listen을 false를 사용하는 경우는 다음과 같다.

1. 상태 변경에 따른 리스닝이 필요하지 않은 경우

2. Provider.of를 호출하는 위치에서 리빌드를 방지하고자 하는 경우

 

이 코드에서는 버튼이 클릭될 때 Provider로 Counter 객체의 increment()를 호출을 하기를 원한다. 상태를 리스닝할 필요가 없다. 따라서 listen을 false로 해야 한다.

 

      onPressed: () {
        Provider.of<Counter>(context, listen).increment();
      },

 

댓글
공지사항