[Riverpod] #3 Provider의 사용 방법

2023. 4. 12. 21:50Flutter

반응형
Provider를 사용하려면 먼저 ref 객체를 가져와야 한다.

이 ref를 통해 위젯 또는 다른 provider와 상호작용 할 수 있다.

 

Provider로부터 ref 객체 전달받기

모든 Provider는 ref 객체를 파라미터로 전달받는다.

final provider = Provider((ref) {
  // 다른 프로바이더 객체를 얻기위해 ref를 사용
  final repository = ref.watch(repositoryProvider);
  return repository.get();
})

이 파라미터 ref 객체는 다른 객체로 전달할 수도 있다.

 

일반적인 사용 사례는 StateNotifier에 전달하는 것이다.

final counterProvider = StateNotifierProvider<Counter, int>((ref) {
  return Counter(ref);
});

class Counter extends StateNotifier<int> {
  Counter(this.ref) : super(0);

  final Ref ref;

  void increment() {
    // Counter는 다른 프로바이더를 읽기 위해 "ref"를 사용할 수 있다.
    final repository = ref.read(repositoryProvider);
    repository.post('...');
  }
}

위젯에서 ref 가져오기

위젯은 기본적으로 ref 파라미터를 가지고 있지 않다. 그러나 riverpod은 위젯에서 ref를 얻을 수 있는 방법을 제공한다.

 

StatelessWidget 대신 ConsumerWidget상속

consumerWidget은 StatelessWidget과 거의 동일하다. 차이점은 build 메소드의 두번째 파라미터에 ref객체가 있다는 점이다.

class HomeView extends ConsumerWidget {
	const HomeView({super.key});
    
    @override
    Widget build(BuildContext context, Widget ref) {
    	// ref를 사용해 Provider 수신
        final counter = ref.watch(counterProvider);
        return Text('$counter');
    }
}

StatefulWidget+State 대신 ConsumerStateWidget + ConsumerState 상속받기

ConsumerWidget과 마찬가지로, CousumerStatefulWidget + ConsumerState는 StatefulWidget + State와 거의 동일하다. 유일한 차이는 State에 ref가 있다는 것이다.

이번엔 ref가 빌드 메소드의 파라미터가 아닌 ConsumerState 객체의 프로퍼티로 전달된다.

class HomeView extends ConsumerStatefulWidget {
  const HomeView({Key? key}) : super(key: key);

  @override
  HomeViewState createState() => HomeViewState();
}

class HomeViewState extends ConsumerState<HomeView> {
  @override
  void initState() {
    super.initState();
    // "ref"는 StatefulWidget의 모든 생명주기 상에서 사용할 수 있다
    ref.read(counterProvider);
  }

  @override
  Widget build(BuildContext context) {
    // "ref"는 build 메소드 안에서 프로바이더를 수신하기위해 사용할 수 있다
    final counter = ref.watch(counterProvider);
    return Text('$counter');
  }
}

ref를 사용하여 Provider와 상호작용하기

ref에는 크게 3가지의 주요 용도가 있다.

 

  • ref.watch : provider의 값을 가져오고 변화를 모니터링한다. 값이 변경되면 widget을 rebuild 하거나 값을 구독하고 있는 위치에 상태값을 전달한다. 상태 변화시 rebuild하기 때문에 성능 이슈가 발생할 수 있지만, 변화를 즉각 반영해야 할 때 사용한다.
  • ref.listen : watch와 동일하게 변화를 모니터링하지만 widget을 rebuild하거나 다른 곳에 상태값을 전달하지 않는다. provider가 변경될 때마다 새 페이지로 이동하거나 모달을 표시하는 등의 커스텀한 작업을 수행할 수 있다.
  • ref.read : 변화를 모니터링하지 않으며 provider의 값을 가져온다. onClick과 같은 클릭 이벤트에서 변경 내용을 무시하면서 provider의 값이 필요할 때 유용하다.

가능하면 기능을 구현할 때는 ref.read보다 ref.listen이나 ref.watch를 사용하는 것이 좋다.
ref.watch를 사용하면 앱이 reactive리액티브와 declarative선언형에 가까워지고 유지보수가 더 쉬워진다.

 

  • watch 메소드는 비동기적(asynchronously)으로 호출해서는 안된다. 예를들면 ElevatedButton의 onPressed 함수 내부에서, 그리고 initState와 다른 State의 생명주기 내부에서도 watch 메소드를 사용해서는 안된다.
    이런 경우에는 ref.read를 사용하는 것이 좋다.
  • listen 메소드는 비동기적으로 호출해서는 안된다. 예를 들면 ElevatedButton의 onPressed 함수 내부에서 호출해서는 안된다. 또한 initState 및 기타 상태 수명 주기 내부에서도 사용해서는 안된다. 
  • ref.read는 반응형이 아니므로 가급적 사용하지 않는 것이 좋다.
    ref.read 메소드는 watch 또는 listen을 사용하면 문제가 발생할 수 있는 경우를 위해 존재한다. 가능하면 거의 항상 watch, listen을 사용하는 것이 좋으며, 특히 watch를 사용하는 것이 좋다.

 

반응형