Flutter State

State Management

Flutter에서 상태 관리는 애플리케이션의 UI와 데이터 상태를 동기화하고 유지하는 중요한 개념입니다. 다양한 상태 관리 기법이 있으며, 각각의 방법은 특정 요구사항과 복잡도에 따라 선택할 수 있습니다. 여기에서는 Flutter의 주요 상태 관리 기법들을 소개하겠습니다.

1. setState

가장 기본적인 상태 관리 방법으로, StatefulWidget을 사용하여 상태를 관리합니다. 작은 애플리케이션이나 간단한 위젯에서 사용하기 적합합니다.

import 'package:flutter/material.dart';

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: CounterPage(),
    );
  }
}

class CounterPage extends StatefulWidget {
  @override
  _CounterPageState createState() => _CounterPageState();
}

class _CounterPageState extends State<CounterPage> {
  int _counter = 0;

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

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        child: Text(
          'Counter: $_counter',
          style: TextStyle(fontSize: 24),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        child: Icon(Icons.add),
      ),
    );
  }
}

2. Provider

Provider는 중간 복잡도의 애플리케이션에서 상태 관리를 더 쉽게 할 수 있도록 도와주는 패키지입니다. InheritedWidget을 기반으로 하며, 상태를 공유하고 하위 위젯 트리에 전파합니다.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: CounterPage(),
    );
  }
}

class Counter extends ChangeNotifier {
  int _count = 0;

  int get count => _count;

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

class CounterPage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    final counter = Provider.of<Counter>(context);

    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        child: Text(
          'Counter: ${counter.count}',
          style: TextStyle(fontSize: 24),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: counter.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

3. Riverpod

Riverpod은 Provider의 개선된 버전으로, 더 안전하고 테스트하기 쉬운 상태 관리를 제공합니다.

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

void main() {
  runApp(ProviderScope(child: MyApp()));
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: CounterPage(),
    );
  }
}

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

class CounterPage extends ConsumerWidget {
  @override
  Widget build(BuildContext context, ScopedReader watch) {
    final counter = watch(counterProvider).state;

    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        child: Text(
          'Counter: $counter',
          style: TextStyle(fontSize: 24),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () => context.read(counterProvider).state++,
        child: Icon(Icons.add),
      ),
    );
  }
}

4. Bloc

Bloc은 Business Logic Component의 약자로, 이벤트 기반 상태 관리를 제공합니다. 대규모 애플리케이션에서 사용하기 적합하며, 상태와 비즈니스 로직을 분리합니다.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      home: BlocProvider(
        create: (_) => CounterBloc(),
        child: CounterPage(),
      ),
    );
  }
}

class CounterBloc extends Bloc<CounterEvent, int> {
  CounterBloc() : super(0);

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

abstract class CounterEvent {}

class Increment extends CounterEvent {}

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

    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        child: BlocBuilder<CounterBloc, int>(
          builder: (context, count) {
            return Text(
              'Counter: $count',
              style: TextStyle(fontSize: 24),
            );
          },
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          counterBloc.add(Increment());
        },
        child: Icon(Icons.add),
      ),
    );
  }
}

5. GetX

GetX는 경량화된 상태 관리 패키지로, 상태 관리, 의존성 주입, 라우팅 등을 지원합니다. 간단하면서도 강력한 기능을 제공합니다.

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

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

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      title: 'Flutter Demo',
      home: CounterPage(),
    );
  }
}

class CounterController extends GetxController {
  var count = 0.obs;

  void increment() {
    count++;
  }
}

class CounterPage extends StatelessWidget {
  final CounterController controller = Get.put(CounterController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text('Counter'),
      ),
      body: Center(
        child: Obx(
          () => Text(
            'Counter: ${controller.count}',
            style: TextStyle(fontSize: 24),
          ),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

결론

Flutter에서 상태 관리는 애플리케이션의 규모와 복잡도에 따라 다양한 방법을 사용할 수 있습니다. 간단한 애플리케이션에서는 setState를, 중간 복잡도에서는 ProviderRiverpod을, 대규모 애플리케이션에서는 Bloc이나 GetX를 사용하는 것이 일반적입니다. 각 방법의 장단점을 고려하여 적절한 상태 관리 방법을 선택하는 것이 중요합니다.

Leave a Reply

Your email address will not be published. Required fields are marked *