Flutter Riverpod

강정우·2023년 5월 29일
0

Flutter&Dart

목록 보기
41/87

Riverpod

flutter pub add riverpod
  • 위 코드로 라이브러리를 설치하면 된다.

  • 또한 위 라이브러리는 provider를 개발한 개발자가 만든 라이브러리이며 provider보다 조금 더 편리하고 유연한 상태관리를 위한 라이브러리로 업그레이드 됐다.

  • 이때 riverpod(다트), flutter_riverpod가 따로 있으니 반드시 flutter_riverpod로 설치해줘야한다.

  • 이와 또 다른 유명한 라이브러리는 getX정도가 있겠고 마치 vue.js의 상태관리 라이브러리가 vuex와 pinia가 매우 유망하고 pinia로 넘어가는 시대처럼 RiverPod를 많이 쓰지만 최근에는 getX를 더 많이 사용하는 것 같다. (뇌피셜)

  • 일단 기본적인 Riverpod를 공부하고 추후 getX를 공부하여 포스팅하겠다.

  • 공급자라는 객체를 생성할 수 있다.

  • 리버포드 패키지가 제공하는 클래스에 기반하여 객체를 생성하는 것이다.

  • 이제 이 공급자는 동적 값를 제공할 수 있고 결국 그 값을 바꿀 수 있는 메서드도 제공한다.

  • 그리고 우리 앱에서 어떤 위젯에서든 공급자에 연결된 소비자를 설정할 수 있다.

  • 이는 리버포드 패키지가 자동으로 연결하는 것이다.

  • 이 소비자 위젯에서 해당 공급자 값에 대한 변화를 listen할 수 있다.

  • 혹은 공급자가 제공하는 메서드를 호출해 그러한 변화를 트리거할 수도 있다.

App에 적용

  • 어떤 프레임웤이든 state를 관리하는 라이브러릴 사용할 땐 항상 app에 해당되는 부분에 warp을 하였다.

  • react에서는 <Provider>로 <APP>을 감싸고 vue.js에서는 app.use()로 넣어줬다. 마찬가지이다.

  • ProviderScope 위젯엔 child 속성이 있는데 여기에 우리가 사용하는 App 위젯을 넣어주면 App wide하게 사용이 가능하다.

폴더 생성

  • lib 폴더에 provider 폴더를 생성하고 이제 여기서 app wide하게 전역으로 사용할 수 있는 공급자 객체를 설정하는 곳이다.

파일 작성

import 'package:riverpod/riverpod.dart';
  • 위 패키지에서 제공하는 공급자 객체를 인스턴스화 하고 이를 변수에 저장해야한다.

  • 그리고 이 공금자 객체는 반드시 최소 1개의 함수를 매개변수로 갖는다.

  • 그리고 또 그 함수는 ProviderRef를 매개변수로 받는다. 이때 이름 그대로 변수의 타입은 ProviderRef 타입이다.

  • 그리고 return 값은 우리가 전역 state로 사용하고 싶은 값을 return하면 된다.

state 값 사용하기

  • 이떄 가장 큰 변화는 바로 StatefulWidet => ConsumerStatefulWidet 이라고 변환하면 된다. 이때 StatelessWidget => ConsumerWidget 이다.

  • 이렇게 바꿔주면 비로소 provider를 사용할 준비가 되었다.
    바로 build 함수에서 사용가능하다. 마치 StatefulWidet에서 widet 객체값으로 다양한 속성에 접근했던 것 처럼 ref 객체로 provider에 접근가능하다. => CunsumerState 클래스니까

read, watch

  • 그리고 공식문서에서는 읽어오는 기능을 하는 read와 watch 중 watch를 더 강권한다. 왜냐하면 로직이 변하더라도 버그가 더 적기 때문이다.

  • 그리고 read, watch 메서드 둘다 공급자를 매개변수로 넣어줘야하고 이때 import한 provider 객체를 넣어주면 된다.

StateNotifierProvider

  • 앞서 사용했던 그냥 Provider는 state 값이 변하지 않을 때 사용하는 값이다. 만약 state 값이 변한다면 StateNotifierProvider객체를 사용해야한다.

  • 그리고 이 StateNotifierProvider는 항상 StateNotifier와 함께 사용된다. 마치 StatefulWidget이 State class와 함께 사용되던 것 처럼 말이다.

  • 그래서 StateNofifier를 상속받는 클래스는 사실 아무렇게나 이름을 지어도 되지만 전통적으로 Notifier라는 접미어는 반드시 붙어있어야한다.
    그리고 StateNofifier에 들어갈 데이터 타입은 Riverpod에게 어떤 종류의 데이터가 StateNofifier에 의해 관리되고 StateNotifierProvider에 의해 최종적으로 반환되는 값이어야한다.

  • 위 코드에서는 생성자 함수에 아무것도 선언하지 않고 다만 colon : 으로 initializing을 해줬다. 이때 StateNotifier에 StateNotifierProvider에서 반환할 타입을 넣주는데 이때 초기화도 마찬가지로 해당 타입에 맞춰서 초기화를 해주면 된다.

StateNotifier

  • 하지만 위에서 메서드로 값을 임의로 변경할 수 없다. 따라서 2가지 방법이 있는데

  • StateNotifier가 갖는 데이터 타입은 앞으로 해당 state에 다룰 데이터 타입을 넣어주면 된다.

  • 또한 StateNotifier는 기존의 컴포넌트 클래스의 생성자 함수 선언 방식과는 조금 다르기 때문에 유의깊게 살펴봐야한다.

  • 그리고 위 사진에서는 빼먹은 것이 있는데 바로 super 메서드 내부에 초기화해주는 값에 const 키워드를 빼먹었다. 이를 추가해줘야하는 이유는 river pod로 관리되는 state값들은 mutate 되면 안 되기 때문이다. 즉, 직접적으로 수정하면 안 되고 새로운 state 객체를 생성한 후 대체해야한다.
    따라서 혹시나 실수로 직접적으로 수정하려고 할 때 막아줄 수 있는 보험역할로서 const 키워드가 들어가는 것이다.
    이 문장은 밑에 setFilter 메서드가 state를 설정하는 방식을 보면 쉽게 이해할 수 있다.

state

  • 위 state 객체는 마치 widget과 ref와 비슷하며 StateNotifier가 제공하는 객체이다.
    그리고 state객체는 StateNotifier가 들어있는 데이터 타입의 값을 갖는다.
    그리고 이 state를 절대 직접 변환하면 안 된다. 오직 할당 = 연산만 가능하다.

  • 그래서 위 코드는 state에 .contains 메서드를 사용하여 매개변수로 들어온 값이 있다면 빼고 없다면 추가해주는 메서드이다.

  • 앞서 언급 했듯 state객체를 절대 직접변환하면 안 되기에 그래서 remove 메서드 대신 where 메서드를 사용한다.
    where 메서드는 항상 새 배열을 생성한다. => 기존 데이터를 건들지 않는다.
    참고로 where 메서드로 remove 함수와 같은 효과를 내는 메서드는 위 코드와 같다. where 함수는 주어진 배열에서 주어진 조건이 참인 것 만을 반환하기 때문이다.

  • 또한 ... spread 연산자로 기존에 값을 모두 가져오고 추가적으로 매개변수로 들어온 값을 넣어주기 위함이다.

  • 이때 타입이 ary가 아닌 Map이라면?!

  • 마찬가지로 spread 연산자를 하고 그 밑에 매개변수로 들어오는 값을 추가해주면 된다.

  • 이렇게 하면 비로소 edit class가 완성 되었다. 이제 실제 Provier 클래스와 연결하면 된다.

StateNotifierProvider 타입지정

  • 여기 StateNotifierProvider 공급자도 마찬가지로 함수를 매개변수로 받고 그 함수의 매개변수는 ref이다.
    그리고 반환 값은 당연 위에서 data를 edit 한 ~~Notifier 인스턴스가 들어와한다. 위의 Provider와 같은 원리이다. 실제 공급자가 데이터를 들고갈 데이터가 와야한다.

  • 그리고 반환값이 있다면 반환값에 대한 type을 지정해줘야한다.
    첫번째는 인스턴스의 타입이고 두번째는 인스턴스가 반환하는 데이터 타입을 넣어줘야한다.

  • 그리고 이렇게 지정해두면 다른 consumer에서 사용했을 때 보다 나은 경험을 제공할 것이다.

ConsumerWidget

  • 앞서 언급 했듯 StatelessWidget을 대체하는 위젯으로 이때 build 메서드에는 추가적으로 WidgetRef 타입의 ref 변수가 추가되어야한다.

  • 그리고 실행은 .read() 메서드를 사용하여 가져온다. watch는 여기서 적절하지 않다. 메서드를 사용하는데 메서드는 객체의 메서드이고 이를 watch 주시하는 것은 메모리 낭비이기 때문에 read를 공급자를 불러들인 다음 해당 메서드를 사용하면 된다.

  • 또한 initState와 같은 1번 실행되는 함수에서도 watch 함수를 사용할 필요가 없다. 왜? => 코드 자체가 1번만 실행되기 때문에

profile
智(지)! 德(덕)! 體(체)!

0개의 댓글