flutter

flutter provider.of vs Consumer

햎피 2022. 6. 28. 22:21
반응형

flutter에서 provider와 consumer를 언제 사용해야할지, 두개의 차이점이 무엇인지 궁금했다.

Provider는 데이터를 전달해주는 역할을 한다.

 

Consumer는 2가지 상황에서 provider 대신에 사용된다.

 

 1.  Provider의 자손인 BuildContext를 가지고 있지 않아서 Provider.of를 사용할 수 없을 때, Provider에서 값을 얻을 수 있게 한다. 

document에서 이렇게 말하는데, 이게 무슨 말이지 헷갈릴 것이다...

@override
Widget build(BuildContext context) {
  return ChangeNotifierProvider(
    create: (_) => Foo(),
    child: Text(Provider.of<Foo>(context).value),
  );
}

다음의 상황처럼, provider를 생성 했는데, 소비해야할 때 나타난다.

위의 코드는 Provider.of가 BuildContext와 함께 불러졌기 때문에 ProviderNotFoundException 에러가 날 것이다.

이 때 Consumer widget을 사용한다.

 

이렇게!!

@override
Widget build(BuildContext context) {
  return ChangeNotifierProvider(
    create: (_) => Foo(),
    child: Consumer<Foo>(
      builder: (_, foo, __) => Text(foo.value),
    },
  );
}

Consumer를 사용하면 ProviderNotFoundException 에러가 나지 않을 것이다.

 

 

2. 전체 위젯을 rebuild 하지 않고, 업데이트가 필요한 widget만 rebuild 함으로서 Provider 보다 성능을 더 높일 수 있다.

만약 Provider.of에서 listen:true로 설정하면 관련 위젯들은 Provider의 값이 바뀔때마다 rebuild 될 것이다.

따라서 굳이 필요없는 rebuild를 계속 하게 될 수도 있다.

 

예를 들면,

@override
 Widget build(BuildContext context) {
   return FooWidget(
     child: BarWidget(
       bar: Provider.of<Bar>(context),
     ),
   );
 }

다음의 코드에서는 BarWidget만 Provider.of의 리턴값에따라 달라진다. 하지만 Bar가 변하면 BarWidget과 FooWidget이 모두 rebuild 될 것이다.

이상적으로는 BarWidget만 rebuild 되면 된다. 

이때 Consumer를 사용하는 것이다.

@override
 Widget build(BuildContext context) {
   return FooWidget(
     child: Consumer<Bar>(
       builder: (_, bar, __) => BarWidget(bar: bar),
     ),
   );
 }

관련된 widget인 BarWidget만 Consumer로 래핑해준다.

만약 Bar가 업데이트되면, BarWidget만 rebuild 될 것이다.

 

그렇다면 아래 코드와 같이 만약 FooWidget만 provider와 관련되어있다면 어떻게 해야할까?

 @override
 Widget build(BuildContext context) {
   return FooWidget(
     foo: Provider.of<Foo>(context),
     child: BarWidget(),
   );
 }

이때도 Consumer를 사용할 수 있고, optional child argument를 사용해서 해결 할 수 있다.

 

@override
 Widget build(BuildContext context) {
   return Consumer<Foo>(
     builder: (_, foo, child) => FooWidget(foo: foo, child: child),
     child: BarWidget(),
   );
 }

BarWidget이 builder의 바깥쪽에서 만들어졌다.

그리고 BarWidget instance가 마지막 파라미터로서 builder로 전달되었다.

 

이 의미는 builder가 새로운 값을 가지고 다시 불러졌을 때, 새로운 instance인 BarWidget은 생성되지 않을 것이다.

BarWidget을 rebuild 할 필요가 없음을 알려주므로, 만약 Foo가 변하면, FooWidget만 rebuild 될 것이다.

반응형