English | French | Portuguรชs | ็ฎไฝไธญๆ | Espaรฑol | ํ๊ตญ์ด | เฆฌเฆพเฆเฆฒเฆพ | ๆฅๆฌ่ช | Turkish | Italian
InheritedWidget์ ๋ ์ฝ๊ฒ ์ฌ์ฉํ๊ณ ๋ณด๋ค ์ฌ์ฌ์ฉํ ์ ์๋๋ก ๋ง๋ค์ด์ง ๋ํผ์ ๋๋ค.
InheritedWidget์ ์ง์ ์์ฑํ๋ ๊ฒ ๋์ provider
๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ, ์๋์ ๊ฐ์ ์ด์ ์ ๊ฐ์ง ์ ์์ต๋๋ค.
- ๋ฆฌ์์ค์ ๋จ์ํ๋ ํ ๋น/ํด์
- ์ง์ฐ ๋ก๋ฉ(lazy-loading)
- ํด๋์ค๋ฅผ ์๋ก ๋ง๋ค ๋ ๋ง๋ค ๋งค๋ฒ ์์ฑํด์ผํ๋ ๋ถ๋ถ์ ํฌ๊ฒ ์ค์
- devtool ์นํ์ : Provider๋ฅผ ์ฌ์ฉํ๋ฉด Application State๊ฐ Flutter devtool์ ํ์๋จ
- ์ด๋ฌํ InheritedWidget๋ค์ ์๋น(consume)ํ๋ ์ผ๋ฐ์ ์ธ ๋ฐฉ๋ฒ์ ์ ์ (Provider.of/Consumer/Selector ์ฐธ๊ณ )
- ๋ณต์ก์ฑ์ด ๊ธฐํ๊ธ์์ ์ผ๋ก ์ฆ๊ฐํ๋ ์์ ๋งค์ปค๋์ฆ(listening mechanism)์ ๊ฐ์ง ํด๋์ค์ ๋ํ ํ์ฅ์ฑ ํฅ์(์ : ์๋ฆผ ๋ฐ์ก์ O(N)์ธ ChangeNotifier).
provider
์ ๋ํ ์์ธํ ๋ด์ฉ์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํด์ฃผ์ธ์.
์ฐธ๊ณ ํญ๋ชฉ:
- The official Flutter state management documentation :
provider
+ ChangeNotifier ์ฌ์ฉ๋ฒ์ ๋ํ ์ผ์ผ์ด์ค - flutter architecture sample :
provider
+ ChangeNotifier๋ฅผ ์ฌ์ฉํ ์ฑ ๊ตฌํ provider
๋ฅผ ์ํคํ ์ฒ์ ํ์ฉํ flutter_bloc์ Mobx
-
์ด์
FutureProvider
์StreamProvider
๋ฅผ ์ํinitialData
๊ฐ ํ์ํฉ๋๋ค.๋ง์ด๊ทธ๋ ์ด์ ์ ์ํด ์๋์ ๊ฐ์ ๋ด์ฉ์
FutureProvider<int>( create: (context) => Future.value(42), child: MyApp(), ) Widget build(BuildContext context) { final value = context.watch<int>(); return Text('$value'); }
์ด์ ์ด๋ ๊ฒ ์์ฑํฉ๋๋ค.
FutureProvider<int?>( initialValue: null, create: (context) => Future.value(42), child: MyApp(), ) Widget build(BuildContext context) { // be sure to specify the ? in watch<int?> final value = context.watch<int?>(); return Text('$value'); }
-
ValueListenableProvider
๊ฐ ์ญ์ ๋์์ต๋๋ค.๋ง์ด๊ทธ๋ ์ด์ ์, ๋์
Provider
๋ฅผValueListenableBuilder
์ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.ValueListenableBuilder<int>( valueListenable: myValueListenable, builder: (context, value, _) { return Provider<int>.value( value: value, child: MyApp(), ); } )
Providers๋ ๋จ์ํ ๊ฐ์ ๋ ธ์ถ ์์ผ์ค ๋ฟ๋ง ์๋๋ผ, ๊ฐ์ ์์ฑ(create), ์์ (listen) ๊ทธ๋ฆฌ๊ณ ํด์ (dispose)๋ฅผ ํ ์ ์๋๋ก ํฉ๋๋ค.
์ ๊ท ์์ฑํ ๊ฐ์ฒด๋ฅผ ๋
ธ์ถํ๊ธฐ ์ํด provider์ ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ์ฌ์ฉํ์ธ์.
๋ง์ฝ ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ถ๋ค๋ฉด .value
์์ฑ์๋ฅผ ์ฌ์ฉํ์ง๋ง์ธ์. ๊ทธ๋ ์ง ์์ผ๋ฉด ์๋์น ์์ ๋ถ์์ฉ์ด ๋ํ๋ ์ ์์ต๋๋ค.
๊ฐ์ ์์ฑํ๊ธฐ ์ํด .value
์์ฑ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ์ ๋ฐ๋์งํ์ง ์์์ง ํ์ธํ๋ ค๋ฉด StackOverflow ๋ต๋ณ์ ํ์ธํ์ธ์.
- DO :
create
์์์ ์ ๊ท ์ค๋ธ์ ํธ๋ฅผ ์์ฑํ์ธ์.
Provider(
create: (_) => MyModel(),
child: ...
)
- DON'T : ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ธฐ ์ํด
Provider.value
๋ฅผ ์ฌ์ฉํ์ง ๋ง์ธ์.
ChangeNotifierProvider.value(
value: MyModel(),
child: ...
)
-
DON'T : ์๊ฐ์ ๋ฐ๋ผ ๋ณ๊ฒฝ๋ ์ ์๋ ๋ณ์๋ก ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ง ๋ง์ธ์.
๋ง์ฝ ๊ทธ๋ ๊ฒ ์์ฑํ์๋ค๋ฉด, ์์ฑ๋ ๊ฐ์ฒด๋ ๊ฐ์ด ๋ณํํด๋ ์ ๋ฐ์ดํธ๋์ง ์์ต๋๋ค.
int count;
Provider(
create: (_) => MyModel(count),
child: ...
)
๋ง์ฝ ์๊ฐ์ ๋ฐ๋ผ ๋ณ๊ฒฝ๋ ์ ์๋ ๋ณ์๋ฅผ ๊ฐ์ฒด์ ์ ๋ฌํ๋ ค๋ฉด
ProxyProvider
์ฌ์ฉ์ ๊ณ ๋ คํ์ธ์.
int count;
ProxyProvider0(
update: (_, __) => MyModel(count),
child: ...
)
NOTE:
provider์ create
/update
์ฝ๋ฐฑ์ ์ฌ์ฉํ ๋, ์ด ์ฝ๋ฐฑ์ด ๊ธฐ๋ณธ์ ์ผ๋ก Lazyํ๊ฒ ํธ์ถ๋๋ค๋ ์ ์ ์ ์ํด์ผํฉ๋๋ค.
์ฆ, ํด๋น ๊ฐ์ ํ ๋ฒ ์ด์ ํธ์ถํ๊ธฐ ์ ์๋ create
/update
์ฝ๋ฐฑ์ด ํธ์ถ๋์ง ์์ต๋๋ค.
์ด ๋์์ lazy
ํ๋ผ๋ฏธํฐ๋ฅผ ์ฌ์ฉํด ์ผ๋ถ ๋ก์ง์ ์ฌ์ ์ฐ์ฐ(pre-compute)ํ๊ณ ์ ํ๋ ๊ฒฝ์ฐ ๋นํ์ฑํ ๋ ์ ์์ต๋๋ค.
MyProvider(
create: (_) => Something(),
lazy: false,
)
๊ฐ์ฒด ์ธ์คํด์ค๊ฐ ์ด๋ฏธ ์์ฑ๋์๊ณ , ํด๋น ๊ฐ์ฒด๋ฅผ ๋
ธ์ถ์ํค๊ธธ ์ํ๋ ๊ฒฝ์ฐ provider์ .value
์์ฑ์๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ด ๊ฐ์ฅ ์ข์ต๋๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด ๊ฐ์ฒด๊ฐ ์์ง ์ฌ์ฉ๋๊ณ ์๋ ๋์ค์ dispose
๋ฉ์๋๊ฐ ํธ์ถ๋ ์ ๋ ์์ต๋๋ค.
- DO : ์ด๋ฏธ ์กด์ฌํ๋ ChangeNotifier๋ฅผ ๊ณต๊ธ(provide)ํ๊ธฐ ์ํด์
ChangeNotifierProvider.value
๋ฅผ ์ฌ์ฉํ์ธ์.
MyChangeNotifier variable;
ChangeNotifierProvider.value(
value: variable,
child: ...
)
- DON'T : ์ด๋ฏธ ์กด์ฌํ๋ ChangeNotifier๋ฅผ ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ์ฌ์ฉํด์ ์ฌ์ฌ์ฉํ์ง ๋ง์ธ์.
MyChangeNotifier variable;
ChangeNotifierProvider(
create: (_) => variable,
child: ...
)
๊ฐ์ ์ฝ๋ ๊ฐ์ฅ ์ฌ์ด ๋ฐฉ๋ฒ์ BuildContext์ ํ์ฅ ๋ฉ์๋๋ฅผ ํ์ฉํ๋ ๊ฒ์ ๋๋ค.
context.watch<T>()
: ์์ ฏ์ดT
์ ๋ณํ๋ฅผ ๊ฐ์งํ ์ ์๋๋ก ํฉ๋๋ค.context.read<T>()
:T
๋ฅผ ๋ณํ ๊ฐ์ง ์์ด return ํฉ๋๋ค.context.select<T, R>(R cb(T value))
:T
์ ์ผ๋ถ ์์ ์์ญ์ ๋ํด์๋ง ์์ ฏ์ด ๋ณํ๋ฅผ ๊ฐ์งํ ์ ์๋๋ก ํฉ๋๋ค.
๋ํ watch
์ ์ ์ฌํ๊ฒ ๋์ํ๋ ์ ์ ๋ฉ์๋(static method)์ธ Provider.of<T>(context)
๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค.
Provider.of<T>(context, listen: false)
์ฒ๋ผ listen
ํ๋ผ๋ฏธํฐ๋ฅผ false
๋ก ํ๋ฉด read
์ ์ ์ฌํ๊ฒ ๋์ํฉ๋๋ค.
context.read<T>()
๋ ๊ฐ์ด ๋ณ๊ฒฝ๋์์ ๋ ์์ ฏ์ ์ฌ๋น๋ํ์ง ์์์ผ๋ก StatelessWidget.build
/State.build
์์์ ํธ์ถ๋ ์ ์์์ ์ ์ํ์ธ์.
๋ฐ๋ฉด, ์ด๋ฌํ ๋ฉ์๋๋ค ๋ฐ์์๋ ์์ ๋กญ๊ฒ ํธ์ถ๋ ์ ์์ต๋๋ค.
์ด๋ฌํ ๋ฉ์๋๋ค์ ์ ๋ฌ๋ BuildContext
์ ๊ด๋ จ๋ ์์ ฏ์์ ์์ํด ์์ ฏ ํธ๋ฆฌ์์ ๋ฐ๊ฒฌ๋๋ฉฐ,
๋ฐ๊ฒฌ๋ ๊ฐ์ฅ ๊ฐ๊น์ด T
ํ์
๋ณ์๋ฅผ ๋ฐํํฉ๋๋ค. (์๋ฌด๊ฒ๋ ์ฐพ์ ์ ์๋ ๊ฒฝ์ฐ ์์ธ๊ฐ ๋ฐ์ ํฉ๋๋ค.)
์ด ์์ ์ O(1)์ ๋๋ค. ์์ ์ ์์ ฏ ํธ๋ฆฌ๋ฅผ ์์ฐจ์ ์ผ๋ก ํ์ํ๋ ์ผ์ด ํฌํจ ๋์ด์์ง ์์ต๋๋ค.
์ด ์์ ฏ์ ์ฒซ ๋ฒ์งธ ์์์ธ ๊ฐ ๋
ธ์ถํ๊ธฐ์์ ๋
ธ์ถ๋ String
์ ์ฝ๊ณ "Hello World."๋ฅผ ๋ ๋ํฉ๋๋ค.
class Home extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Text(
// Don't forget to pass the type of the object you want to obtain to `watch`!
context.watch<String>(),
);
}
}
์ด๋ฌํ ๋ฉ์๋๋ค์ ์ฌ์ฉํ๋ ๋์ ์, ์ฐ๋ฆฌ๋ Consumer์ Selector๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์ด ๊ธฐ๋ฅ์ ์ฑ๋ฅ์ ์ต์ ํํ๊ฑฐ๋, provider์ BuildContext
ํ์ ํญ๋ชฉ์ ์ ๊ทผํ๊ธฐ ์ด๋ ค์ธ ๋ ์ ์ฉํ๊ฒ ํ์ฉํ ์ ์์ต๋๋ค.
๋ ๋ง์ ์ ๋ณด๊ฐ ํ์ํ๋ค๋ฉด ์๋์ ๊ฐ์ ๋ฌธ์๋ฅผ ์ฐธ๊ณ ํ์ธ์.
๋๋๋ก ์ฐ๋ฆฌ๋ provider๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ๋ฅผ ์ง์ํ๊ณ ์ถ์ ์๋ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด provider ์ธ๋ถ ๋ฑ ๋ค์ํ ์์น์์ ์ฌ์ฉ๋ ์ ์๋ ์์ ฏ์ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค.
๊ทธ๋ ๊ฒ ํ๊ธฐ ์ํด์, context.watch
/context.read
์ ํธ์ถํ ๋ generic ํ์
๋์ nullable ํ์
์ ์ฌ์ฉํฉ๋๋ค.
์๋ฅผ ๋ค์ด ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ ๊ฒฝ์ฐ,
context.watch<Model>()
๋งค์นญ๋๋ provider๋ฅผ ์ฐพ์ง ๋ชปํ ๊ฒฝ์ฐ ProviderNotFoundException
์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค.
๋์ ์๋์ ๊ฐ์ด ์ฌ์ฉํ๋ฉด,
context.watch<Model?>()
๋งค์นญ๋๋ provider๋ฅผ ์ฐพ์ง ๋ชปํ๋๋ผ๋ ์์ธ๋ฅผ ๋ฐ์์ํค๋ ๋์ , null
์ ๋ฐํํฉ๋๋ค.
๊ท๋ชจ๊ฐ ํฐ ์ดํ๋ฆฌ์ผ์ด์
์์ ๋ง์ ๊ฐ์ ์ฃผ์
ํ๋ฉด Provider
๊ฐ ๊ธ๊ฒฉํ๊ฒ ์ค์ฒฉ๋ ์ ์์ต๋๋ค.
Provider<Something>(
create: (_) => Something(),
child: Provider<SomethingElse>(
create: (_) => SomethingElse(),
child: Provider<AnotherThing>(
create: (_) => AnotherThing(),
child: someWidget,
),
),
),
์ด๋ฅผ ์๋์ ๊ฐ์ด ์์ฑํ ์ ์์ต๋๋ค.
MultiProvider(
providers: [
Provider<Something>(create: (_) => Something()),
Provider<SomethingElse>(create: (_) => SomethingElse()),
Provider<AnotherThing>(create: (_) => AnotherThing()),
],
child: someWidget,
)
๋ ์ฝ๋๋ ์์ ํ ๋์ผํ๊ฒ ๋์ํฉ๋๋ค.
MultiProvider
๋ ์ค์ง ์ฝ๋์ ์ธ๊ด์ ๋ฐ๊ฟ์ค ๋ฟ์
๋๋ค.
3.0.0 ๋ฒ์ ผ๋ถํฐ ์๋ก์ด provider์ธ ProxyProvider
๊ฐ ์ถ๊ฐ๋์์ต๋๋ค.
ProxyProvider
๋ ๋ค๋ฅธ provider๋ค์ ์ฌ๋ฌ ๊ฐ์ ํ๋์ ๊ฐ์ฒด๋ก ๋ฌถ์ด Provider
๋ก ์ ๋ฌํ๋ provider์
๋๋ค.
๊ทธ๋ฌ๋ฉด ํด๋น ์ ๊ท ๊ฐ์ฒด๋ ์ฐ๋ฆฌ๊ฐ ์์กดํ๋ provider ์ค ํ๋๊ฐ ์ ๋ฐ์ดํธ๋ ๋๋ง๋ค ์ ๋ฐ์ดํธ๋ฉ๋๋ค.
์๋ ์์ ์์๋ ๋ค๋ฅธ provider์์ ์จ counter
๋ฅผ ๊ธฐ๋ฐ์ผ๋ก translations
๋ฅผ ๋น๋ํ๊ธฐ ์ํด ProxyProvider
๋ฅผ ์ฌ์ฉํ๊ณ ์์ต๋๋ค.
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(create: (_) => Counter()),
ProxyProvider<Counter, Translations>(
update: (_, counter, __) => Translations(counter.value),
),
],
child: Foo(),
);
}
class Translations {
const Translations(this._value);
final int _value;
String get title => 'You clicked $_value times';
}
์ด๊ฒ์ ์๋์ ๊ฐ์ ๋ค์ํ ๋ณํ์ด ๊ฐ๋ฅํฉ๋๋ค.
-
ProxyProvider
vsProxyProvider2
vsProxyProvider3
, ...ํด๋์ค ์ด๋ฆ ๋ค์ ์ซ์๋
ProxyProvider
๊ฐ ์์กดํ๋ ๋ค๋ฅธ ๊ณต๊ธ์์ ์์ ๋๋ค. -
ProxyProvider
vsChangeNotifierProxyProvider
vsListenableProxyProvider
, ...๋ชจ๋ ๋น์ทํ๊ฒ ๋์ํ์ง๋ง,
ChangeNotifierProxyProvider
๋ ๊ฐ์ ๊ทธ ๊ฒฐ๊ณผ๋ฅผProvider
๋ฅผ ๋ณด๋ด๋ ๋์ ,ChangeNotifierProvider
๋ก ๋ณด๋ ๋๋ค.
Flutter๋ ์ง์ ๋ ์์ ์ ์์ ฏ ํธ๋ฆฌ๊ฐ ์ด๋ค ๊ฒ์ธ์ง ๋ณด์ฌ์ฃผ๋ devtool์ด ํจ๊ป ์ ๊ณต๋ฉ๋๋ค.
provider๋ ์์ ฏ์ด๊ธฐ ๋๋ฌธ์ ๋ง์ฐฌ๊ฐ์ง๋ก devtool์์ ๋ณผ ์ ์์ต๋๋ค.
์ฌ๊ธฐ์์ ํ provider๋ฅผ ํด๋ฆญํ๋ฉด ํด๋น provider๊ฐ ๋ ธ์ถํ๊ณ ์๋ ๊ฐ์ ๋ณผ ์ ์์ต๋๋ค.
(example
ํด๋๋ฅผ ์ฌ์ฉํ๋ devtool ์คํฌ๋ฆฐ์ท)
๊ธฐ๋ณธ์ ์ผ๋ก devTool์ toString
์ ์์กดํ๊ธฐ ๋๋ฌธ์ ๊ธฐ๋ณธ ์ค์ ์ธ "Instance of MyClass"๋ก ๋ณด์ฌ์ง๋๋ค.
๋ณด๋ค ์ ์ฉํ๊ฒ ์ฌ์ฉํ๊ธฐ ์ํด์, ๋ค์๊ณผ ๊ฐ์ ๋ ๊ฐ์ง ์๋ฃจ์ ์ด ์์ต๋๋ค.
-
Flutter์ Diagnosticable API๋ฅผ ์ฌ์ฉํ์ธ์.
๋๋ถ๋ถ์ ๊ฒฝ์ฐ ๊ฐ์ฒด์ debugFillProperties๋ก ์ปค์คํ ํ DiagnosticableTreeMixin๋ฅผ ์ฌ์ฉ
class MyClass with DiagnosticableTreeMixin { MyClass({this.a, this.b}); final int a; final String b; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); // list all the properties of your class here. // See the documentation of debugFillProperties for more information. properties.add(IntProperty('a', a)); properties.add(StringProperty('b', b)); } }
-
toString
์ ์ฌ์ ์(override) ํ์ธ์.๋ง์ฝ DiagnosticableTreeMixin๋ฅผ ์ฌ์ฉํ ์ ์๋ค๋ฉด (Flutter๋ฅผ ์ฌ์ฉํ์ง ์๋ ํจํค์ง ๋ฑ),
toString
๋ฅผ ์ฌ์ ์ํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.์ด๊ฒ์ DiagnosticableTreeMixin๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ณด๋ค ์ฝ์ง๋ง, ๊ฐ์ฒด์ ์ธ๋ถ์ ๋ณด๋ฅผ ํ์ฅํ๊ฑฐ๋ ์ถ์ํ ์ ์๋ ๋งํผ ๋ณด๋ค ๋ ๊ฐ๋ ฅํฉ๋๋ค.
class MyClass with DiagnosticableTreeMixin { MyClass({this.a, this.b}); final int a; final String b; @override String toString() { return '$runtimeType(a: $a, b: $b)'; } }
์ด ์์ธ๋ ๋ค์ ํธ์ถ๋์ง ์๋ ์๋ช ์ฃผ๊ธฐ(life-cycle)์์ provider๋ฅผ ๊ฐ์งํ๋ ค๊ณ ํ๊ธฐ ๋๋ฌธ์ ๋ฐ์ํฉ๋๋ค.
๋๋ฌธ์ build
์ ๊ฐ์ ๋ค๋ฅธ ์๋ช
์ฃผ๊ธฐ์์ ์ฌ์ฉํ๊ฑฐ๋, ์
๋ฐ์ดํธ์ ๊ด๋ จ ์์์ ๋ช
์ํด์ฃผ์ด์ผํฉ๋๋ค.
๋๋ฌธ์ ์๋์ ๊ฐ์ด ์์ฑํ๋ ๋์ ,
initState() {
super.initState();
print(context.watch<Foo>().value);
}
์ด๋ ๊ฒ ์์ฑํ ์ ์์ต๋๋ค.
Value value;
Widget build(BuildContext context) {
final value = context.watch<Foo>().value;
if (value != this.value) {
this.value = value;
print(value);
}
}
์ด๋ ๊ฐ์ด ๋ณ๊ฒฝ๋ ๋๋ง๋ค(๊ทธ๋ฆฌ๊ณ ๋ณ๊ฒฝ๋ ๋๋ง) 'value
๊ฐ ์ถ๋ ฅ๋ฉ๋๋ค.
๋๋ ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ ์ ์์ต๋๋ค.
initState() {
super.initState();
print(context.read<Foo>().value);
}
์ด๋ value
๋ฅผ ํ๋ฒ ์ถ๋ ฅํ๊ณ ์
๋ฐ์ดํธ๋ฅผ ๋ฌด์ํฉ๋๋ค.
์ ๊ณต๋ ๊ฐ์ฒด์ ReassembleHandler
๋ฅผ ๊ตฌํํ ์ ์์ต๋๋ค.
class Example extends ChangeNotifier implements ReassembleHandler {
@override
void reassemble() {
print('Did hot-reload');
}
}
๊ทธ ํ ์ผ๋ฐ์ ์ผ๋ก provider
์ ํจ๊ป ์ฌ์ฉํฉ๋๋ค.
ChangeNotifierProvider(create: (_) => Example()),
ChangeNotifier๋ฅผ ์ฌ์ฉํ๋ฉฐ ์ ๋ฐ์ดํธํ ๋ ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ฌด์จ ์ผ์ด ์ผ์ด๋๊ณ ์๋ ๊ฑฐ์ฃ ?
์์ ฏ ํธ๋ฆฌ๊ฐ ๋น๋๋๋ ๋์ ํ์ ํญ๋ชฉ ์ค ํ๋์์ ChangeNotifier๋ฅผ ์์ ํ๊ณ ์๊ธฐ ๋๋ฌธ์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
์ผ๋ฐ์ ์ผ๋ก ์ด๋ฌํ ์ํฉ์ notifier ์์ future๊ฐ ์ ์ฅ๋ ์ํ์์ http ์์ฒญ์ ์์ํ ๋ ๋ฐ์ํฉ๋๋ค.
initState() {
super.initState();
context.read<MyNotifier>().fetchSomething();
}
์ํ ์ ๋ฐ์ดํธ๊ฐ ๋๊ธฐํ๋์ด์์ผ๋ฏ๋ก ์ด ์์ ์ ํ์ฉ๋์ง ์์ต๋๋ค.
์ด๋ ์ฆ, ์ด๋ค ์์ ฏ์ ๋ณ๊ฒฝ์ด ์ผ์ด๋๊ธฐ ์ ์ ๋น๋๋ ์ ์์ผ๋ฉฐ(์ค๋๋ ๊ฐ์ ๋ฐ์), ๋ ์ด๋ค ์์ ฏ์ ๋ณ๊ฒฝ์ด ์๋ฃ๋ ํ์ ๋น๋๋ ์ ์์ต๋๋ค(์๋ก์ด ๊ฐ์ ๋ฐ์). ์ด๋ก์ธํด UI์ ๋ถ์ผ์น๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก, ์ด๋ ํ์ฉ๋์ง ์์ต๋๋ค.
๋์ ์ ์ฒด ํธ๋ฆฌ์ ๋์ผํ๊ฒ ์ํฅ์ ๋ฏธ์น๋ ์์น์์ ๋ณ๊ฒฝ์ ์ํํด์ผํฉ๋๋ค.
-
๋ชจ๋ธ์ provider ์์ฑ์
create
์ธ์ ์์์ ์ง์ ์ํํ๊ธฐ :class MyNotifier with ChangeNotifier { MyNotifier() { _fetchSomething(); } Future<void> _fetchSomething() async {} }
์ธ๋ถ ๋ณ์๊ฐ ์๋ ๊ฒฝ์ฐ ์ ์ฉํฉ๋๋ค.
-
ํ๋ ์ ๋์ ๋น๋๊ธฐ์์ผ๋ก ์ํํ๊ธฐ :
initState() { super.initState(); Future.microtask(() => context.read<MyNotifier>().fetchSomething(someValue); ); }
์ฝ๊ฐ ๋ ์ด์์ ์ด์ง๋ง, ๋ณ๊ฒฝ ์ฌํญ์ ๋งค๊ฐ๋ณ์๋ฅผ ์ ๋ฌํ ์ ์์ต๋๋ค.
๋ณต์กํ ์ํ์ ๊ฒฝ์ฐ ChangeNotifier๋ฅผ ์จ์ผํ๋์?
์๋๋๋ค.
๋ชจ๋ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ์ํ๋ฅผ ๋ํ๋ผ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด ๋์ฒด ๊ตฌ์กฐ๋ก Provider.value()
์ StatefulWidget
๋ฅผ ๊ฒฐํฉํ์ฌ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋ ์์๋ ์ด๋ฌํ ๊ตฌ์กฐ๋ฅผ ์ฌ์ฉํ ๋ฐ์ฆ ์ฌ๋ก์ ๋๋ค.
class Example extends StatefulWidget {
const Example({Key key, this.child}) : super(key: key);
final Widget child;
@override
ExampleState createState() => ExampleState();
}
class ExampleState extends State<Example> {
int _count;
void increment() {
setState(() {
_count++;
});
}
@override
Widget build(BuildContext context) {
return Provider.value(
value: _count,
child: Provider.value(
value: this,
child: widget.child,
),
);
}
}
๋ค์ ์์ ์ ํตํด ์ํ๋ฅผ ์ฝ์ ์ ์์ต๋๋ค.
return Text(context.watch<int>().toString());
๋ํ ๋ค์๊ณผ ๊ฐ์ด ์ํ๋ฅผ ์์ ํ ์ ์์ต๋๋ค.
return FloatingActionButton(
onPressed: () => context.read<ExampleState>().increment(),
child: Icon(Icons.plus_one),
);
๋๋ ์ง์ provider๋ฅผ ๋ง๋ค ์๋ ์์ต๋๋ค.
๋ค. provider
๋ provider๋ฅผ ์์ ํ๊ฒ ๊ตฌ์ฑํ๋ ์์ ์ปดํฌ๋ํธ๋ค์ ๋ชจ๋ ๊ณต๊ฐํ๊ณ ์์ต๋๋ค.
์ด๋ ์๋์ ๊ฐ์ ๊ฒ๋ค์ ํฌํจํฉ๋๋ค.
-
์ด๋ค ์์ ฏ์ด๋์ง
MultiProvider
์ ํจ๊ป ๋์ํ๋๋ก ๋ง๋ค์ด์ฃผ๋SingleChildStatelessWidget
. ์ด ์ธํฐํ์ด์ค๋package:provider/single_child_widget
์ ์ผ๋ถ๋ก ๋ ธ์ถ๋ฉ๋๋ค. -
context.watch
๋ฅผ ํ ๋ ์ป์ ์ ์๋ ์ผ๋ฐ์ ์ธInheritedWidget
์ธ InheritedProvider.
๋ค์์ ValueNotifier
๋ฅผ ์ํ๋ก ์ฌ์ฉํ๋ ์ฌ์ฉ์ ์ง์ provider์ ์์
๋๋ค.
https://gist.github.com/rrousselGit/4910f3125e41600df3c2577e26967c91
context.watch
๋ฅผ ์ฌ์ฉํ๋ ๋์ , ๊ฐ์ฒด์ ํน์ ํ ๋ถ๋ถ ๋ง์ ์ถ์ ํ๋ context.select
๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์๋ฅผ ๋ค์ด ๋ค์๊ณผ ๊ฐ์ด ์์ฑํ๋ค๋ฉด,
Widget build(BuildContext context) {
final person = context.watch<Person>();
return Text(person.name);
}
name
์ด ์๋ ๋ค๋ฅธ ํ๋กํผํฐ๊ฐ ๋ณ๊ฒฝ๋์ด๋ ์์ ฏ์ด ์ฌ๋น๋๋ ๊ฒ์
๋๋ค.
๋์ ์ context.select
๋ฅผ ์ฌ์ฉํด name
ํ๋กํผํฐ๋ง ์ถ์ ํ๊ฒํ๋ฉด,
Widget build(BuildContext context) {
final name = context.select((Person p) => p.name);
return Text(name);
}
์ด๋ ๊ฒ ํ๋ฉด name
ํ๋กํผํฐ๊ฐ ์๋ ๋ณํ๊ฐ ๋ฐ์ํ๋๋ผ๋ ๋ถํ์ํ๊ฒ ์์ ฏ์ ์ฌ๋น๋ํ์ง ์์ต๋๋ค.
์ ์ฌํ๊ฒ Consumer/Selector๋ฅผ ์ฌ์ฉํ ์๋ ์์ต๋๋ค. ์ด๋ค์ด ๊ฐ์ง๊ณ ์๋ child
๋งค๊ฐ๋ณ์๋ ์์ ฏ ํธ๋ฆฌ์ ํน์ ๋ถ๋ถ๋ง ์ฌ๋น๋ํ ์ ์๋๋ก ํด์ค๋๋ค.
Foo(
child: Consumer<A>(
builder: (_, a, child) {
return Bar(a: a, child: child);
},
child: Baz(),
),
)
์ ์์์์ A
๊ฐ ์
๋ฐ์ดํธ ๋์์ ๋ ์ค์ง Bar
๋ง ์ฌ๋น๋๋ฉ๋๋ค. Foo
๋ ๋ถํ์ํ๊ฒ ์ฌ๋น๋๋์ง ์์ต๋๋ค.
์์ต๋๋ค. ์ฌ๋ฌ provider๊ฐ ๋์ผํ ํ์ ์ ๊ณต์ ํ ์ ์์ง๋ง, ์์ ฏ์ ๊ฐ์ฅ ๊ฐ๊น์ด ์์ provider ํ๋ ๋ง์ ๊ฐ์ ธ์ฌ ์ ์์ต๋๋ค.
๋์ ๋ provider์๊ฒ ๋ช ์์ ์ผ๋ก ๋ค๋ฅธ ํ์ ์ ์ ๊ณตํ๋ฉด ์ข์ต๋๋ค.
์๋์ ๊ฐ์ด ์์ฑํ๋ ๋์ ,
Provider<String>(
create: (_) => 'England',
child: Provider<String>(
create: (_) => 'London',
child: ...,
),
),
์ด๋ ๊ฒ ์์ฑํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
Provider<Country>(
create: (_) => Country('England'),
child: Provider<City>(
create: (_) => City('London'),
child: ...,
),
),
๋ค, ์์ฑ ์ ์ ๊ณต๋ ๊ตฌํ๊ณผ ํจ๊ป ์ธํฐํ์ด์ค๊ฐ ์ฌ์ฉ๋ ๊ฒ์์ ๋ํ๋ด๋ ํ์ ํํธ๋ฅผ ์ปดํ์ผ๋ฌ์ ์ ๊ณตํด์ผ ํฉ๋๋ค.
abstract class ProviderInterface with ChangeNotifier {
...
}
class ProviderImplementation with ChangeNotifier implements ProviderInterface {
...
}
class Foo extends StatelessWidget {
@override
build(context) {
final provider = Provider.of<ProviderInterface>(context);
return ...
}
}
ChangeNotifierProvider<ProviderInterface>(
create: (_) => ProviderImplementation(),
child: Foo(),
),
provider
๋ ๋ค๋ฅธ ๊ฐ์ฒด ํ์
์ ๋ํด ๋ช ๊ฐ์ง ๋ค๋ฅธ "provider"๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋ชจ๋ ๊ฐ์ฒด์ ๋ฆฌ์คํธ๋ ์ฌ๊ธฐ์์ ํ์ธํ ์ ์์ต๋๋ค.
์ด๋ฆ | ์ค๋ช |
---|---|
Provider | The most ๊ธฐ๋ณธ์ ์ธ provider ํํ. ์ด๋ค ๊ฐ์ด๋ ๊ฐ์ ๊ฐ์ ๋ ธ์ถ์ํต๋๋ค. |
ListenableProvider | Listenable ๊ฐ์ฒด๋ฅผ ์ํ ํน์ํ provider. ListenableProvider๋ listener๊ฐ ํธ์ถ๋ ๋๋ง๋ค ์ค๋ธ์ ํธ๋ฅผ ์์ ํ๊ณ ์ค๋ธ์ ํธ์ ์ข ์๋ ์์ ฏ์ ์ฌ๊ตฌ์ฑํ๋๋ก ์์ฒญํฉ๋๋ค. |
ChangeNotifierProvider | ChangeNotifier์ฉ ListenableProvider ์ฌ์. ํ์ํ ๋ ์๋์ผ๋ก ChangeNotifier.dispose ๋ฅผ ํธ์ถํฉ๋๋ค. |
ValueListenableProvider | ValueListenable์ ์์ ํ๊ณ , ValueListenable.value ๋ง์ ๋
ธ์ถํฉ๋๋ค. |
StreamProvider | ์คํธ๋ฆผ์ ์์ ํ๊ณ ์ต์ ๊ฐ์ ํ์ํฉ๋๋ค. |
FutureProvider | Future ๋ฅผ ๋ฐ๊ณ , ์์ฑ๋์์ ๋ ์์กด๋ ๊ฐ์ฒด๋ฅผ ์
๋ฐ์ดํธํฉ๋๋ค. |
๋ด ์ ํ๋ฆฌ์ผ์ด์ ์์ ๋๋ฌด ๋ง์ ํ๋ก๋ฐ์ด๋๋ฅผ ๊ฐ์ง๊ณ ์์ด StackOverflowError ์์ธ๊ฐ ๋ฐ์ํฉ๋๋ค. ์ด๋ป๊ฒ ํด๊ฒฐํ๋ฉด ์ข์๊น์?
๋ง์ฝ ๋งค์ฐ ๋ง์ ํ๋ก๋ฐ์ด๋(150 ์ด์)๊ฐ ์๋ ๊ฒฝ์ฐ, ํ ๋ฒ์ ๋ง์ ์์ ฏ์ ๋น๋๋๊ธฐ ๋๋ฌธ์ ๋๋ฐ์ด์ค์ ๋ฐ๋ผ์๋ StackOverflowError
์์ธ๊ฐ ๋ฐ์๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค.
์ด ๊ฒฝ์ฐ ๋ช ๊ฐ์ง ํด๊ฒฐ์ฑ ์ด ์์ต๋๋ค.
-
๋ง์ฝ ์ ํ๋ฆฌ์ผ์ด์ ์ ์คํ๋์ ํ๋ฉด์ด ์๋ ๊ฒฝ์ฐ, provider๋ฅผ ํ๋ฒ์ ๋ง์ดํธํ๋ ๋์ ์๊ฐ์ด ์ง๋จ์ ๋ฐ๋ผ ๋ง์ดํธํด ๋ณด์ธ์.
์๋์ ์์ ์ฝ๋์ ๊ฐ์ ๊ฒฝ์ฐ:
MultiProvider( providers: [ if (step1) ...[ <lots of providers>, ], if (step2) ...[ <some more providers> ] ], )
์คํ๋์ ์คํฌ๋ฆฐ ์ ๋๋ฉ์ด์ ์์ ์๋์ ๊ฐ์ด ์ฒ๋ฆฌํด๋ณด์ธ์.
bool step1 = false; bool step2 = false; @override initState() { super.initState(); Future(() { setState(() => step1 = true); Future(() { setState(() => step2 = true); }); }); }
-
MultiProvider
๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒ์ ๊ณ ๋ คํด๋ณด์ธ์.MultiProvider
๋๊ฐ ํ๋ก๋ฐ์ด๋์ ์ฌ์ด์ ์์ ฏ์ ์ถ๊ฐํ๋ ๊ฒ
์ผ๋ก ๋์ํฉ๋๋ค.MultiProvider
๋ฅผ ์ฌ์ฉํ์ง ์๋ ๊ฒฝ์ฐ๋StackOverflowError
์ ์ด๋ฅผ ๋๊น์ง์ ์ ํ์ ๋๋ฆด ์๊ฐ ์์ต๋๋ค.