본문 바로가기
Flutter

[Flutter/플러터] Riverpod와 StateNotifier에 대해

by 얘리밍 2022. 9. 28.
320x100
728x90

 

 

stateNotifier는 changeNotifier의 업그레이드 버전이라고 볼 수 있다.

그럼 먼저 changeNotifier에 대해 알아보자..

 

 

 

 

▶   ChangeNotifier 란?

          변경사항을 알리고 싶을 때마다 리스너에게 알림을 제공하는 클래스

 

 

  • notifyListeners() 클래스에 변화가 있을 때 해당 메서드를 호출할 수 있다.
  • ValueNotifier단일 값만을 전달하는 ChangeNotifier의 일종이다(오직 하나의 변경된 값만을 전달할 수 있다.)

 

class MyValueNotifier extends ValueNotifier<int>{
  //하나의 값만을 갖고 있을 수 있음
  int getValue() => value;
}

class MyChangeNotifier extends ChangeNotifier{
  // multiple한 값들 가능 
}

 

 

 

이 두가지를 사용했을 때의 몇가지 문제점이 존재한다..

 

    1.  ChangeNotifier와 ValueNotifier는 mutable 이라 클래스 외부 누구나 notifier의 상태를 변경 가능하다. 

            →  이는 원하지 않은 상호작용을 야기할 수 있다.

 

    2.  ChangeNotifier를 사용하는 동안에는 notifyListeners()를 일일이 호출해야 한다.

 

 

 

class ItemNotifier extends ChangeNotifier {
  final List<String> _items = <String>[];
  int _size = 0;

  	...

  void add(String value) {
    _items.add(value);
    _size++;
    notifyListeners();
  }
  
}

 

 


 

 

 

이러한 단점들을 보완한 것이 StateNotifier이다 

 

▶  StateNotifier의  장점

  • 본질적으로 immutable 속성
  • 이전상태새로운 상태를 비교하며 이를 리스너에게 자동으로 알림
  • 단일 데이터의 수정 point 이다 

 

 

StateNotifier가 무엇인지 알았으니 이제 사용해보자..

 

먼저, pubspec.yaml 파일에 아래 두개의 dependency를 추가하자

// # pubspec.yaml

dependencies:
    state_notifier:
    flutter_state_notifier:

 

 

간단한 counter 클래스를 가지고 StateNotifier를 활용해볼 예정이다.

 

riverpod 패키지를 import 해 주고, StateNotifier 옆에 전달하고자 하는 변수의 형을 넣어준다

그 다음 그 밑에, StateCounter 인스턴스를 global 하게 선언해준다

 

 

counter.dart

import 'package:flutter_riverpod/flutter_riverpod.dart';

class StateCounter extends StateNotifier<int> {
  StateCounter() : super(0);

  void increment() {
    state++;
  }

  void decrement() {
    state--;
  }
}

final StateCounter myCounter = StateCounter();

 

 

 

이제 StateNotifierBuilder를 사용해서 바뀐 값을 위젯에 적용하는 방법을 알아보겠다.

 

 

 

먼저 버튼 클릭을 통해 값을 증가해 줄테니, onpressed에 myCounter를 증가해보자..

floatingActionButton: FloatingActionButton(
        onPressed: () => myCounter.increment(),
        ...
),

 

 

 

다음으로는 변경하고자 하는 위젯을 StateNotifierBuilder로 감싸고

builder를 통해 값을 전달한다..

 body: StateNotifierBuilder(
        stateNotifier: myCounter,
        builder: (context, value, child) {
          return Center(
            child: Text(value.toString()),
          );
        },
      ),

 

 

 

 

최종 코드

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

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

  @override
  State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      ...
      floatingActionButton: FloatingActionButton(
        // 1. 
        onPressed: () => myCounter.increment(),
        child: const Icon(Icons.add),
      ),
      body: StateNotifierBuilder(
        stateNotifier: myCounter,
        builder: (context, value, child) {
         // 2. 
          return Center(
            child: Text(value.toString()),
          );
        },
      ),
    );
  }
}

 

riverpod를 사용할 때, 물론 ChangeNotifier와 ValueNotifier를 사용할 수 있지만

StateNotifier를 사용하는 것을 권장하고 있다..

728x90
반응형