티스토리 뷰

- flutter

flutter - Riverpod 라이브러리

나둥식 2022. 11. 15. 11:44
🔎 Riverpod
: Flutter의 패키지 중 하나로, 상태관리를 위한 패키지이다.

 

1️⃣ 패키지 설치

dependencies:
  flutter:
    sdk: flutter
  flutter_riverpod: ^2.0.0-dev.9

https://riverpod.dev/ko/docs/getting_started

 

 

 

2️⃣ 사용예시1 - 상태변경 x

 

① 프로바이더 상태 저장

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// provider -> 공급자
// provider는 창고(Repository)에 데이터를 공급
final numProvider = Provider((_) => 2);

void main() {
  runApp(
    // 위젯에서 프로바이더를 사용하고 읽기위해
    // 앱 전체적으로 "ProviderScope" 위젯을 감싸줘야 합니다.
    // 여기에 프로바이더의 상태가 저장됩니다.
    ProviderScope(
      child: MyApp(),
    ),
  );
}

- final로 Provider를 numProvider로 초기화한 후,

- main 메서드에 MyApp을 ProviderScope로 감싸준다. (프로바이더를 사용하기 위해 프로바이더의 상태 저장)

 

 

② ConsumerWidget 상속

// a컴포넌트 // 컨슈머(데이터 소비자) - 상태를 가지고 그림을 그림 ==> 소비자는 공급자(Provider)에게 데이터를 요청한다.
// ==> 공급자는 창고에서 데이터를 꺼내서 돌려준다.
// StatelessWidget 대신에 Riverpod의 ConsumerWidget을 상속받아 사용합니다. (다시 그리고싶은 것에 사용)
class AComponent extends ConsumerWidget {
  const AComponent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // WidgetRef ref로 provider에 접근 가능 (= 공급자에게 접근 -> 공급자가 데이터 가져옴)
    // 소비를 한번만 할 때 read 사용!
    // watch는 numProvider의 값이 변경될 때마다 rebuild됨
    int num = ref.read(numProvider);

    return Container(
      color: Colors.yellow,
      child: Column(
        children: [
          Text("AComponent"),
          Expanded(
            // TEXT를 Expanded하면 text가 커지니까 align으로 정렬 후 확장!
            child: Align(
              child: Text(
                "${num}", // num 바인딩
                style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

- 다시 그리고싶은 AComponent에 ConsumerWidget을 상속하고,

- WidgetRef ref로 Provider(공급자)에 접근한다.  ( => 공급자가 데이터를 가져옴 )

- int num = ref.read(numProvider) :  소비를 한 번만 할 때 read 사용

- "${num}" 바인딩 하기

 

⭐상태를 main에서 호출했기 때문에 전체 리빌드되어야 하지만, 라이브러리는 알아서 상태가 리빌드되는 것을 막아줌

= ProviderScope 위젯

 

 

 

 

3️⃣ 사용예시2 - 상태가 변하는 Provider

 

① AComponent

int num = ref.watch(numProvider);

- ref.watch :  값이 변경될 때마다 rebuild 됨

 

 

② BComponent

// b컴포넌트 // 서플라이어(공급자)
class BComponent extends ConsumerWidget {
  const BComponent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.blue,
      child: Column(
        children: [
          Text("BComponent"),
          Expanded(
            child: Align(
              //Container로 하면 버튼이 커짐!
              child: ElevatedButton(
                onPressed: () {
                  final repo = ref.read(
                      numProvider.notifier); //stateProvider일때만 notifier 사용가능
                  repo.state = repo.state + 5;
                },
                child: Text(
                  "숫자증가",
                  style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

- final repo = ref.read(numProvider.notifier);   :  stateProvider일때만 notifier 사용가능

- repo.state = repo.state + 5;

 

 

🔎 WidgetRef를 이용해 읽기
: WidgetRef를 이용해서 Provider에 접근이 가능함

ref.watch
- 반응형으로 Provider의 값이 변경되면 다시 rebuild 됨
- 비동기적으로 호출하거나, onTab, initState 등의 생명주기에서 사용 X
- 다른 Provider와 결합할 때 아주 유용함!
- 관찰자, 리스너

ref.read
- Provider의 값을 읽어오기만 함 (읽기전용)
- 값이 변경되어도 별다른 동작을 하지 않음
- 최초에 단 한번만 그려지고 끝남
- build 메소드 내부에서 사용 자제해야 함

ref.listen
- Provider의 값이 변경되면 값을 읽는 것이 아니라 정의한 함수를 실행함
- build 내부나 Provider의 내부에서 사용되어야 함

 

 

 

[ 전체코드 ]

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';

// provider -> 공급자
// provider는 창고(Repository)에 데이터를 공급
//final numProvider = Provider((_) => 2); //상태 변경 불가
final numProvider = StateProvider((_) => 2); //데이터 변경 가능

void main() {
  runApp(
    // 위젯에서 프로바이더를 사용하고 읽기위해
    // 앱 전체적으로 "ProviderScope" 위젯을 감싸줘야 합니다.
    // 여기에 프로바이더의 상태가 저장됩니다.
    ProviderScope(
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: HomePage(),
    );
  }
}

class HomePage extends StatelessWidget {
  const HomePage({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: [
          Expanded(child: AComponent()),
          Expanded(child: BComponent()),
        ],
      ),
    );
  }
}

// a컴포넌트 // 컨슈머(데이터 소비자) - 상태를 가지고 그림을 그림 ==> 소비자는 공급자(Provider)에게 데이터를 요청한다.
// ==> 공급자는 창고에서 데이터를 꺼내서 돌려준다.
// StatelessWidget 대신에 Riverpod의 ConsumerWidget을 상속받아 사용합니다. (다시 그리고싶은 것에 사용)
class AComponent extends ConsumerWidget {
  //final int num;
  const AComponent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    // WidgetRef ref로 provider에 접근 가능 (= 공급자에게 접근 -> 공급자가 데이터 가져옴)
    // 소비를 한번만 할 때 read 사용!
    // watch는 numProvider의 값이 변경될 때마다 rebuild됨
    //int num = ref.read(numProvider);
    int num = ref.watch(numProvider);

    return Container(
      color: Colors.yellow,
      child: Column(
        children: [
          Text("AComponent"),
          Expanded(
            // TEXT를 Expanded하면 text가 커지니까 align으로 정렬 후 확장!
            child: Align(
              child: Text(
                "${num}", // num 바인딩
                style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

// b컴포넌트 // 서플라이어(공급자)
class BComponent extends ConsumerWidget {
  const BComponent({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    return Container(
      color: Colors.blue,
      child: Column(
        children: [
          Text("BComponent"),
          Expanded(
            child: Align(
              //Container로 하면 버튼이 커짐!
              child: ElevatedButton(
                onPressed: () {
                  final repo = ref.read(
                      numProvider.notifier); //stateProvider일때만 notifier 사용가능
                  repo.state = repo.state + 5;
                },
                child: Text(
                  "숫자증가",
                  style: TextStyle(fontSize: 50, fontWeight: FontWeight.bold),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

 

'- flutter' 카테고리의 다른 글

code style 변경  (0) 2022.11.18
Json 데이터로 DTO 생성하기  (0) 2022.11.17
kakao앱 만들기 (6) - 더보기 화면  (0) 2022.11.11
kakao앱 만들기 (5) - 채팅 화면  (0) 2022.11.11
kakao앱 만들기 (4) - 채팅리스트 화면  (0) 2022.11.11
댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
글 보관함