본문 바로가기
프로그래밍/Flutter

[Flutter] 5. Flutter의 "상태 관리"

by iwbap 2024. 6. 25.
728x90

Flutter 학습: 상태 관리

Flutter 애플리케이션을 개발할 때 중요한 부분 중 하나는 상태 관리입니다. 상태 관리를 통해 애플리케이션의 UI와 데이터 간의 일관성을 유지할 수 있습니다. 이번 글에서는 Flutter의 상태 관리 개념, 간단한 상태 관리 방법, 그리고 복잡한 상태 관리 방법에 대해 알아보겠습니다.


1. 상태 관리 개념: State 클래스, setState 메서드

State 클래스와 StatefulWidget: Flutter에서 상태가 변할 수 있는 위젯은 StatefulWidget을 사용하여 정의합니다. StatefulWidget은 상태를 저장하고 변경할 수 있는 State 객체를 가지고 있습니다.

 

State 클래스: State 클래스는 StatefulWidget의 상태를 관리합니다. 상태가 변경되면 UI를 다시 빌드하여 상태 변경을 반영합니다.

setState 메서드: setState 메서드는 상태를 변경하고, 변경된 상태를 반영하기 위해 UI를 다시 빌드하는 역할을 합니다.

 

예제:

[dart]
 
import 'package:flutter/material.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterWidget(),
    );
  }
}

class CounterWidget extends StatefulWidget {
  @override
  _CounterWidgetState createState() => _CounterWidgetState();
}

class _CounterWidgetState extends State<CounterWidget> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('State Management Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
 

위의 예제에서 _CounterWidgetState 클래스는 _counter 상태를 관리하고, setState 메서드를 사용하여 상태를 업데이트합니다.


2. 간단한 상태 관리: Provider 패턴, ChangeNotifier

Provider 패턴: Provider 패턴은 간단하면서도 강력한 상태 관리 방법입니다. provider 패키지를 사용하여 쉽게 상태를 관리할 수 있습니다.

ChangeNotifier: ChangeNotifier는 변경 가능한 상태를 관리하는 클래스입니다. 상태가 변경될 때 리스너에게 알릴 수 있습니다.

 

예제:

1. pubspec.yaml에 provider 추가

[yaml]
 

dependencies:
  flutter:
    sdk: flutter
  provider: ^6.0.0

 

 

2. ChangeNotifier 클래스 정의

[dart]
import 'package:flutter/material.dart';

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }
}
 
 

3. Provider를 사용하여 상태 관리

[dart]
 
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'counter.dart';

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (context) => Counter(),
      child: MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: CounterWidget(),
    );
  }
}

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Provider Example'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Text(
              'You have pushed the button this many times:',
            ),
            Consumer<Counter>(
              builder: (context, counter, child) {
                return Text(
                  '${counter.count}',
                  style: Theme.of(context).textTheme.headline4,
                );
              },
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read<Counter>().increment(),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
 

위의 예제에서 Counter 클래스는 ChangeNotifier를 상속받아 상태를 관리합니다. ChangeNotifierProvider를 사용하여 Counter 객체를 제공하고, Consumer를 사용하여 상태 변경을 감지합니다.


3. 복잡한 상태 관리: BLoC 패턴, Redux

BLoC 패턴: BLoC(Business Logic Component) 패턴은 비즈니스 로직을 별도의 컴포넌트로 분리하여 상태를 관리하는 패턴입니다. flutter_bloc 패키지를 사용하여 BLoC 패턴을 구현할 수 있습니다.

 

예제:

 

1. pubspec.yaml에 flutter_bloc 추가

[yaml]
 
dependencies:
  flutter:
    sdk: flutter
  flutter_bloc: ^7.0.0
 
 

2. BLoC 및 이벤트 정의

[dart]
 
import 'package:flutter_bloc/flutter_bloc.dart';

// 이벤트 정의
abstract class CounterEvent {}
class Increment extends CounterEvent {}

// 상태 정의
class CounterState {
  final int count;
  CounterState(this.count);
}

// BLoC 정의
class CounterBloc extends Bloc<CounterEvent, CounterState> {
  CounterBloc() : super(CounterState(0));

  @override
  Stream<CounterState> mapEventToState(CounterEvent event) async* {
    if (event is Increment) {
      yield CounterState(state.count + 1);
    }
  }
}
 
 

3. BLoC 패턴 사용

[dart]
 
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'counter_bloc.dart';

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: BlocProvider(
        create: (context) => CounterBloc(),
        child: CounterWidget(),
      ),
    );
  }
}

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counterBloc = context.read<CounterBloc>();

    return Scaffold(
      appBar: AppBar(
        title: Text('BLoC Pattern Example'),
      ),
      body: Center(
        child: BlocBuilder<CounterBloc, CounterState>(
          builder: (context, state) {
            return Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: [
                Text('You have pushed the button this many times:'),
                Text(
                  '${state.count}',
                  style: Theme.of(context).textTheme.headline4,
                ),
              ],
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => counterBloc.add(Increment()),
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
 
 
 

Redux: Redux는 상태 관리 라이브러리로, 애플리케이션의 상태를 중앙 집중식으로 관리합니다. flutter_redux 패키지를 사용하여 Redux 패턴을 구현할 수 있습니다.

 

예제:

 

1. pubspec.yaml에 flutter_redux 추가

[yaml]
 
dependencies:
  flutter:
    sdk: flutter
  flutter_redux: ^0.8.0
  redux: ^4.0.0
 
 

2. Redux 상태 및 액션 정의

[dart]
 
// 상태 정의
class AppState {
  final int counter;
  AppState(this.counter);
}

// 액션 정의
class IncrementAction {}

// 리듀서 정의
AppState reducer(AppState state, dynamic action) {
  if (action is IncrementAction) {
    return AppState(state.counter + 1);
  }
  return state;
}
 
 

3. Redux 패턴 사용

[dart]
 
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'redux_state.dart';

void main() {
  final store = Store<AppState>(reducer, initialState: AppState(0));
  runApp(MyApp(store));
}

class MyApp extends StatelessWidget {
  final Store<AppState> store;

  MyApp(this.store);

  @override
  Widget build(BuildContext context) {
    return StoreProvider(
      store: store,
      child: MaterialApp(
        home: CounterWidget(),
      ),
    );
  }
}

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Redux Example'),
      ),
      body: Center(
        child:
728x90