Sign In
공부 내용

Flutter의 상태 관리 - Controller (Provider)

Y
yeji Kim

참고 자료

Controller

컨트롤러는 사용자 입력을 처리하고 모델을 업데이트함.

Provider

Key concepts

ChangeNotifier - listener에게 변화에 대해 알림.
import 'package:flutter/foundation.dart'; class Counter with ChangeNotifier { int _count = 0; int get count => _count; void increment() { _count++; notifyListeners(); } }
Provider - widget tree에서 inject, access
ChangeNotifierProvider
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'counter.dart'; void main() { runApp( ChangeNotifierProvider( create: (context) => Counter(), child: MyApp(), ), ); }
ChangeNotifier가 변하면 dependents를 rebuild함.
Consumer - object가 변하면 스스로를 rebuild함.
import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'counter.dart'; class CounterScreen extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Provider Counter Example'), ), body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ 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: () { Provider.of<Counter>(context, listen: false).increment(); }, tooltip: 'Increment', child: Icon(Icons.add), ), ); } }

사용 목적

위와 같이 동일 상태 (데이터)를 전역적으로 다른 위젯과 공유하기 위해
최상단 위젯에 Provider 제공
void main() { runApp( MultiProvider( providers: [ ChangeNotifierProvider(create: (_) => Counts()), ], child: MyApp(), ), ); }
class Home extends StatelessWidget { @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text('Provider'), ), body: ChangeNotifierProvider( create: (BuildContext context) => Counts(), child: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Counter(), Buttons(), ], ), ), ), ); } }
Provider를 사용하는 위젯
class Counter extends StatelessWidget { @override Widget build(BuildContext context) { print('Counter'); return Text( context.watch<Counts>().count.toString(), style: TextStyle( fontSize: 20, ), ); } }
class Buttons extends StatelessWidget { @override Widget build(BuildContext context) { return Row( mainAxisAlignment: MainAxisAlignment.center, children: [ ElevatedButton( onPressed: () { context.read<Counts>().add(); }, child: Icon(Icons.add)), SizedBox( width: 40, ), ElevatedButton( onPressed: () { context.read<Counts>().remove(); }, child: Icon(Icons.remove)) ], ); } }

Provider의 함수

read - 상태 값을 읽음. 감시하진 않음. Provider의 값을 변경하는 함수에 많이 쓰임.
watch - 상태 값의 변화를 감시함. 상태 값을 사용할 때.
select - 상태 값의 특정 부분 만을 감시함.
변경된 상태 값을 표시하기 위한 rebuild에 많은 비용이 드는데, 이 때 select를 이용하여 특정 값만의 변경을 감시하여 최적화할 수 있음.

Provider 선언하기

단일 Provider
MaterialApp( title: 'Flutter Provider Demo', home: ChangeNotifierProvider( create: (BuildContext context) => CounterProvider(), child: Home(), ), );
다중 Provider
MaterialApp( title: 'Flutter Provider Demo', home: MultiProvider( providers: [ ChangeNotifierProvider( create: (BuildContext context) => CounterProvider(), ), ChangeNotifierProvider( create: (BuildContext context) => TodoProvider(), ), ], child: Home(), ), );

Provider 사용하기

Provider.of
@override Widget build(BuildContext context) { CounterProvider counter = Provider.of<CounterProvider>(context); return Center( child: Text( counter.count.toString(), ), ); }
Provider에 직접 접근해서 받아오기.
현 위젯 전체가 리로드된다.
Consumer
return Center( child: Consumer<CounterProvider>( builder: (context, provider, child) { return Text( provider.count.toString(), ); }, ), );
Consumer를 사용한 해당 부분만 re build됨.
Subscribe to '아무튼-작업일지'
Subscribe to my site to be the first to receive notifications and emails about the latest updates, including new posts.
Join Slashpage and subscribe to '아무튼-작업일지'!
Subscribe
👍