본문 바로가기
Flutter

[Flutter] 플러터 - RiverPod 상태관리(4) StateProvider copyWith() 사용해 보기

by s_hoonee 2024. 1. 30.
반응형

Provider, StateProvider, StateNotifierProvider  사용 예시로 이루어진 시리즈

RiverPod 시리즈 4탄입니다. 아래 게시물을 먼저 확인해 주세요.
https://hooninha.tistory.com/88

 

[Flutter] 플러터 - RiverPod 상태관리(3) StateProvider 여러 값 사용해 보기

기존 포스팅 시리즈 3탄입니다. 아래 게시물을 먼저 확인해 주세요. https://hooninha.tistory.com/87 [Flutter] 플러터 - RiverPod 상태관리(2) StateProvider 단일 값 사용해 보기 기존 포스팅 시리즈 2탄입니다. 아

hooninha.tistory.com

이번 포스팅에는 StateProvider와 copyWith 방식을 사용해 값을 관리하고 메소드를 활용하는 방법에 대해 포스팅하겠습니다.

실습에 필요한 파일은 두개입니다! (이전 포스팅 코드에서 이어서 작성)

 

1. state.dart 파일에 copyWith 메서드 추가

import 'package:flutter_riverpod/flutter_riverpod.dart';

class MyObject {
  final String stringValue;
  final int intValue;

  MyObject({required this.stringValue, required this.intValue});

  // copyWith 메서드 추가
  MyObject copyWith({String? stringValue, int? intValue}) {
    return MyObject(
      stringValue: stringValue ?? this.stringValue,
      intValue: intValue ?? this.intValue,
    );
  }

}

final myObjectProvider = StateProvider<MyObject>((ref) {
  return MyObject(stringValue: '초기값', intValue: 0);
});

copyWith 메소드는 "null-aware 연산자를 활용하여, 생성자의 매개변수가 null인 경우 기존 객체의 값을 사용하도록 설정했습니다. 이렇게 하여 하나의 필드값만 변경이 가능합니다.

2.  copyWith 메서드를 활용하여 상태관리 하기 

read_state_provider.dart 파일에 아래 코드를 작성해줍니다.

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gym_app/page/riverpod_page/stateProvider/state.dart';
import 'package:gym_app/page/riverpod_page/stateProviders/states.dart';

class ReadStateProviders extends ConsumerWidget {
  const ReadStateProviders({super.key});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    /// 이 부분 추가
    final myObject = ref.watch(myObjectProvider);

    return Scaffold(
      appBar: AppBar(
        title: const Text('StateProviders'),
      ),
      body: Center(
        child: Column(
          children: [
            Text(
              myObject.stringValue,
              style: const TextStyle(
                  fontSize: 30, fontWeight: FontWeight.bold, color: Colors.red),
            ),
            Text(
              myObject.intValue.toString(),
              style: const TextStyle(
                  fontSize: 30, fontWeight: FontWeight.bold, color: Colors.red),
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(myObjectProvider.notifier).state =
                    myObject.copyWith(stringValue: '호호호', intValue: 100);
              },
              child: const Text('copyWith 변경 실행'),
            ),
            ElevatedButton(
              onPressed: () {
                ref.read(myObjectProvider.notifier).state = myObject.copyWith(
                  stringValue: '스트링값만',
                );
              },
              child: const Text('copyWith 스트링만 변경 실행'),
            ),
            ElevatedButton(
              onPressed: () {
                ref.refresh(myObjectProvider);
              },
              child: const Text('초기값으로 변경'),
            ),
          ],
        ),
      ),
    );
  }
}

final myObject = ref.watch(myObjectProvider);

지난 포스팅과 다르게 상위에서 myObject를 초기화 하여 각 필드의 값을 불러옵니다.

 

copyWith 메서드는 주로 불변성을 유지하면서 객체를 수정할 때 사용됩니다.

만약 copyWith를 사용하지 않고 직접 속성을 변경하게 된다면, 해당 객체의 불변성을 보장할 책임이 개발자에게 있게 됩니다. 또한 이전 객체와 새로운 객체 간의 차이를 파악하고 추적하는 것이 어려울 수 있습니다.

상태 관리에서 copyWith의 사용은 필수가 아닌 개발자의 편의나 코드 가독성을 위해 사용하는 것이지만, 상태를 변경하는 과정에서의 예기치 못한 버그나 문제를 방지하려면 불변성을 유지하는 것이 좋습니다. 

StateProvider는 상태를 읽기만 가능하고 직접 업데이트를 수행할 수 없는 단순한 상태 제공자입니다. 따라서 상태를 업데이트하려면 StateProvider를 읽어오고 해당 상태에 새로운 값을 할당하여 업데이트해야 합니다.

stateProvider은 이쯤에서 마무리하고 다음 시간부터 StateNotifierProvider 포스팅으로 넘어가겠습니다!