Provider Study 2-3

Sunny·2022년 6월 5일

StateNotifier / Provider

어제 스터디에서 이부분을 설명을 잘해주셨지만, 뭔가 디테일 하게 정리를 해야 할 거 같은 기분이 들어.. 정리를 해둔다

다른 예제처럼 state를 먼저 만들었다.

class BgColorState extends Equatable {
  final Color color;

  BgColorState({required this.color});

  
  List<Object?> get props => [color];

  
  bool get stringify => true;

  BgColorState copyWith({
    Color? color,
  }) {
    return BgColorState(color: color ?? this.color);
  }
}

색상을 변경시키는 state를 만들었다면 이제 stateNotifier를 설명해보겠다
에제를 통해 하나씩 설명해보겠다.

class BgColor extends StateNotifier<BgColorState> {
// state type을 정하기에 문제 방지도 되고 좋음!
//초기 state가 명확한 점!!
  BgColor() : super(BgColorState(color: Colors.blue));
 // initial state setting은 super call에 주는 값이 초기의 state임!  
 // BgColorState를 선언하고 color 값을 할당함!
 
 
 

  
   void changeColor() {
   // 초기의 state 값을 외부에서 바꿔줘야한다면, bgcolor에 state를 전달하고 그 값을 이용해 state setting 해야함
    if (state.color == Colors.blue) {
      state = state.copyWith(color: Colors.black);
        // state라 하는 변수의 statenotifier에 state 값이 저장된다는 것임
       // state 변수를 통해서, state를 access, setting 할 수 있음
    } else if (state.color == Colors.black) {
      state = state.copyWith(color: Colors.red);
    } else {
      state = state.copyWith(color: Colors.blue);
    }
  }
}

코드에 설명을 해놨지만, 난잡하기에 다시 설명하자면,
1. 초기에 state를 설정한다.
2. copyWith를 통해 bgColorState에 color를 state를 통해 바꿔준다. (state를 통해 자동적(?)으로 바꿔주기에! notifyListener를 통해 바꿔줄 필요가 없다!
3. statenotifier에 tate를 명확하게 설정하기에 state type이 명확해진다.
4. statenotifier에는 state 값이 저장된다.
5. state 변수를 통해, state를 access하거나 setting 할 수 있다는 것이다.

개인적으로 proxyprovider처럼 여러가지를 선언하지 않고도 편하게 쓸 수 있다는 것이 좋아보인다.


그렇다면 locator는 뭘까요?

stateNotifier에서 read, watch 기능을 사용하기 위한 것으로 locatorMixin으로 mixin 시키며, serviceLocator라고도 부름!

어떻게사용할까?

state는 위에서 처럼 만드니 counter 사용하는 부분에서 예를 들어보겠다.

class Counter extends StateNotifier<CounterState> with LocatorMixin {
  // read, watch 기능을 사용하기 위한 것 LocatorMixin => serviceLocator라고도 함
  Counter() : super(CounterState(counter: 0));

  void increment() {
    print(read<BgColor>().state);
    // 이벤트 핸들러에서 watch를 계속 써야할 필요가 없으므로 read로 쓰기

    Color currentColor = read<BgColor>().state.color;
    // 다른 state color를 read 하기 위해 사용!

    if (currentColor == Colors.black) {
      state = state.copyWith(counter: state.counter + 10);
    } else if (currentColor == Colors.red) {
      state = state.copyWith(counter: state.counter - 10);
    } else {
      state = state.copyWith(counter: state.counter + 1);
    }
  }

  
  // LocatorMixin에서 상속받은 update 사용
  void update(Locator watch) {
  
    print('in Counter StateNtifier: ${watch<BgColorState>().color}');
    print('in Counter StateNtifier: ${watch<BgColor>().state.color}');

    super.update(watch);
  }
}

예시처럼 사용하면 될 것이다. 위에서 다룬 bgcolor랑 크게 다른 것이 없지만 update 부분을 간단히 설명하면

  1. 다른 object의 update를 listening 해줌 (proxyProvider와 동일한 기능)
  2. dependency가 없기에 외부 widget tree에서도 사용가능
  3. update 내부에서는 read를 쓸 수 없기에, watch를 사용하여 변화를 반응 시켜준다.

(proxyProvider를 사용할 때보다 코드도 간결해지고.. super.update(watch);를 이용하면 많이 스무스한 거 같다.)


마지막은 배경색을 바꾸는 level이다

다른 부분은 동일했지만 여기선 counterstate의 counter를 사용하는데 선언을 final currentCounter = watch().counter; 으로 해서 무난하게 사용했다는 것이였다.


그리고 사용되는 부분에서 statenotifierProvider를 multiProvider로 엮어서 순서에 맞게 설정하고

변수 선언 시에, 아래처럼 하면 된다.

 final colorState = context.watch<BgColorState>();
 final counterState = context.watch<CounterState>();
 final levelState = context.watch<Level>();  

개인적으로 proxyProvider보단 stateNotifier로 만들 것 같다. state로 만들기에 충돌 위험성도 적고... notifierListener를 사용하지 않아도 편하게 바뀌기에 실수도 적을 것 같다.


추가 팁: state 변화시에 연관 되어있는 update 부분은 같이 재빌드가 되네..? ex) print를 찍어놓았을 경우에 그 부분이 모두 다시 출력되었음!

profile
즐거움을 만드는 사람

0개의 댓글