[Flutter] hooks_riverpod

hodu·2024년 3월 17일
0

Flutter

목록 보기
29/30

Riverpod 는 여러 종류의 패키지가 있습니다.

각 패키지마다 사용 목적이 다르며, 어떤 패키지를 설치 할 것인지는 만드려는 앱에 따라 다릅니다.

  • flutter_riverpod: Flutter 앱에 Riverpod 을 사용할 경우의 기본 패키지.
  • riverpod: Flutter 에 관련된 모든 클래스가 완전히 제거된 Riverpod 패키지.
  • hooks_riverpod : flutter_hooks 와 Rivperpod 를 함께 사용하는 패키지.


ref.watch

provider 의 값을 얻어서 변화를 모니터링 할 때 사용합니다.

값이 변경되면, widget 을 re_build 하거나 값을 구독하고 있는 위치에 상태 값을 전달합니다.

상태 변화를 화면에 즉각 반영해야 할 때 사용합니다.

final counterProvider = StateProvider((ref) => 0);

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

  
  Widget build(BuildContext context, WidgetRef ref) {
    // ref를 사용하여 provider 구독
    final counter = ref.watch(counterProvider);

    return Text('$counter');
  }
}

ref.listen

watch 와 동일하게 변화를 모니터링 하지만, widget 을 re_build 하거나 다른 곳에 상태값을 전달하지는 않습니다.

상태 변경이 있을 때, 커스텀한 어떠한 행위를 취해야 할 경우 사용합니다.

아래와 같이 상태 변화 시, SnackBar 등을 호출 할 때, 사용할 수 있습니다.

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

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

  
  Widget build(BuildContext context, WidgetRef ref) {
    ref.listen<int>(counterProvider, (int? previousCount, int newCount) {
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text('Value is ${current.state}')),
      );
    });
    
    return Scaffold(...);
  }
}

ref.read

어떤 부가적인 효과 없이 provider 의 상태 값을 가지고 올 때 사용합니다.

read 는 일반적으로 사용자 상호작용으로 발생가능한 트리거 함수 내부에서 주로 사용합니다.

주로, provider 내부의 callback 함수에 접근할 때 사용합니다.

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

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

  
  Widget build(BuildContext context, WidgetRef ref) {
    return Scaffold(
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // counterProvider의 increment() 메소드를 호출합니다.
          ref.read(counterProvider.notifier).increment();
        },
      ),
    );
  }
}



설치

https://pub.dev/packages/hooks_riverpod

hooks_riverpod

flutter pub add hooks_riverpod

g.dart를 생성하기 위한 패키지

flutter pub add riverpod_generator

generator를 사용하기 위한 패키지

flutter pub add build_runner

annotation 패키지

flutter pub add riverpod_annotation

적용

flutter pub get

generator commaned

dart run build_runner build --delete-conflicting-outputs

코드

  • 기본 구조
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';

class HooksRiverpodEx extends HookConsumerWidget {
  const HooksRiverpodEx({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    return Container();
  }
}
  • main.dart
void main() {
  runApp(const ProviderScope(child: MyApp()));
}
  • counter_provider.dart
import 'package:riverpod_annotation/riverpod_annotation.dart';

part 'counter_provider.g.dart';


class Counter extends _$Counter {
	// state로 관리
  int fetchItem(int value) {
	// 초기화 당시 실행될 로직
    return state = value;
  }

  
  int build() {
    return fetchItem(0);
  }

  // state값 0으로 초기화
  void reset() {
    state = 0;
  }

  // state값 1 증가
  void increase() {
    state++;
  }
}

변수를 생성하여 사용하는 것이 아닌, provider를 통해 상태를 생성하고,

이 상태를 앱 전반에 걸쳐 읽거나 변경할 수 있습니다.

  • hooks_riverpod_ex.dart
    FloatingActionButton 버튼을 통해 counter 값을 1씩 증가시킵니다.
class HooksRiverpodEx extends HookConsumerWidget {
  const HooksRiverpodEx({super.key});

  
  Widget build(BuildContext context, WidgetRef ref) {
    var viewModel = ref.watch(counterProvider);

    return Scaffold(
      body: SafeArea(
          child: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(viewModel.toString()),
            ElevatedButton(
                onPressed: () {
                  ref.read(counterProvider.notifier).reset();
                },
                child: const Text('초기화')),
          ],
        ),
      )),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          ref.read(counterProvider.notifier).increase();
        },
        child: const Icon(Icons.add),
      ),
    );
  }
}



참고

비동기인 경우, 아래와 같이 데이터 결과, 로딩, 에러를 한번에 보여주는 위젯을 제공합니다.

viewModel.when(
            data: (data) {
              return ListView.builder(
                itemCount: data.length,
                itemBuilder: (context, index) {
                  var item = data[index];
                  return ListTile(
                    dense: true,
                    title: Text('item1'),
                    shape: Border(bottom: BorderSide(width: 1)),
                  );
                },
              );
            },
            error: (error, stack) => Center(
              child: CustomErrorWidget(
                error: error,
              ),
            ),
            loading: () => const LoadingIndicator(),
          )




참고 문서:
https://pub.dev/packages/hooks_riverpod

https://velog.io/@udong85/Flutter-Riverpod-%EB%A1%9C-%EC%83%81%ED%83%9C-%EA%B4%80%EB%A6%AC-%ED%95%98%EA%B8%B0-1

https://anpigon.tistory.com/349

profile
Flutter developer

0개의 댓글