์์ํ๊ธฐ โ
์ด ํํ ๋ฆฌ์ผ์์๋ Flutter ๊ธฐ๋ณธ "์นด์ดํฐ" ์ฑ์ MobX๋ก ๋ค์ ๋ง๋ค์ด ๋ด ๋๋ค.

์ค๋นํ๊ธฐ โ
- ํํ ๋ฆฌ์ผ์ ์์ํ๊ธฐ ์ ์ Flutter๊ฐ ์ค์น๋์ด ์๋์ง, ๊ทธ๋ฆฌ๊ณ ์ Flutter ํ๋ก์ ํธ๋ฅผ ๋ง๋๋ ๋ฐฉ๋ฒ์ ์๊ณ ์๋์ง ํ์ธํฉ๋๋ค.
- ์ปดํจํฐ์ ์ Flutter ํ๋ก์ ํธ๋ฅผ ๋ง๋ญ๋๋ค.
์์กด์ฑ ์ค์น โ
pubspec.yaml ํ์ผ์ ๋ค์ dependencies๋ฅผ ์ถ๊ฐํฉ๋๋ค.
dependencies:
mobx: ^2.6.1
flutter_mobx: ^2.3.0์ด์ด์ ๋ค์ dev_dependencies๋ฅผ ์ถ๊ฐํฉ๋๋ค.
dev_dependencies:
build_runner: ^2.16.1
mobx_codegen: ^2.7.8ํ๋ก์ ํธ ํด๋์์ ๋ค์ ๋ช ๋ น์ผ๋ก ํจํค์ง๋ฅผ ๋ชจ๋ ๋ด๋ ค๋ฐ์ต๋๋ค.
flutter pub get์ด์ ๊ฐ๋ฐ์ ํ์ํ ํจํค์ง๊ฐ ๋ชจ๋ ์ค๋น๋์์ต๋๋ค.
์คํ ์ด ์ถ๊ฐํ๊ธฐ โ
์ด์ MobX ์คํ ์ด๋ฅผ ๋ง๋ค์ด ๋ณด๊ฒ ์ต๋๋ค. MobX์์ ์คํ ์ด๋ ์๋ก ๊ด๋ จ๋ Observable ์ํ๋ฅผ ํ๋์ ํด๋์ค๋ก ๋ฌถ๋ ๋ฐฉ๋ฒ์
๋๋ค. ์คํ ์ด๋ฅผ ์ฌ์ฉํ๋ฉด ์ฃผ์(annotation)์ ํ์ฉํ ์ ์์ด ์ฝ๋๊ฐ ๊ฐ๊ฒฐํด์ง๋๋ค. \lib ํด๋์ counter.dart ํ์ผ์ ์๋ก ๋ง๋ค๊ณ ๋ค์ ์ฝ๋๋ฅผ ์ถ๊ฐํฉ๋๋ค.
import 'package:mobx/mobx.dart';
// Include generated file
part 'counter.g.dart';
// This is the class used by rest of your codebase
class Counter = _Counter with _$Counter;
// The store-class
abstract class _Counter with Store {
@observable
int value = 0;
@action
void increment() {
value++;
}
}์ด ์ฝ๋์์ ๋์ฌ๊ฒจ๋ณผ ๋ถ๋ถ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
Store๋ฏน์ค์ธ์ ์ฌ์ฉํ๋ ์ถ์ ํด๋์ค_Counter๊ฐ ์์ต๋๋ค. ์คํ ์ด์ ๊ด๋ จ๋ ์ฝ๋๋ ๋ชจ๋ ์ด ์ถ์ ํด๋์ค ์์ ์์ฑํฉ๋๋ค.build_runner๊ฐ ์์ฑํ ์ฝ๋๋ฅผ ํฉ์น๊ธฐ ์ํดCounterํด๋์ค๋ฅผ ๋ณ๋๋ก ์ ์ธํฉ๋๋ค.- ์์ฑ๋ ์ฝ๋๋
counter.g.dartํํธ ํ์ผ์ ๋ค์ด๊ฐ๋ฉฐ,part์ง์์๋ก ํฌํจํฉ๋๋ค. ์ด ์ง์์๊ฐ ์์ผ๋ฉดbuild_runner๊ฐ ์๋ฌด ๊ฒฐ๊ณผ๋ฌผ๋ ๋ง๋ค์ง ์์ต๋๋ค. ์์ฑ๋ ํ์ผ์๋_$Counter๋ฏน์ค์ธ์ด ๋ค์ด ์์ต๋๋ค.
:::caution
ํ์ผ ์ด๋ฆ์ ๋์๋ฌธ์๋ฅผ ์ ํํ ๋ง์ถฐ์ผ ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ผ๋ฉด build_runner๊ฐ ์๋ฌด ๊ฒฐ๊ณผ๋ฌผ๋ ์์ฑํ์ง ์์ต๋๋ค. ์ฌ๊ธฐ์๋ ํ์ผ ์ด๋ฆ์ด counter.dart์ด๋ฏ๋ก ํํธ ํ์ผ ์ด๋ฆ์ counter.g.dart์ฌ์ผ ํฉ๋๋ค(์๋ฌธ์์์ ์ ์ํ์ธ์).
:::
@observable์ฃผ์์value๋ฅผ Observable(๊ด์ฐฐ ๊ฐ๋ฅํ ์ํ)๋ก ํ์ํฉ๋๋ค.@action์increment()๋ฉ์๋๋ฅผ Action(์ํ๋ฅผ ๋ณ๊ฒฝํ๋ ๋์)์ผ๋ก ํ์ํ๋ ๋ฐ ์ฌ์ฉํฉ๋๋ค.
ํ๋ก์ ํธ ํด๋์์ ๋ค์ ๋ช
๋ น์ ์คํํ๋ฉด, ์ด๋ฏธ ํํธ ํ์ผ๋ก ํฌํจํด ๋ counter.g.dart์ ์ฝ๋๊ฐ ์์ฑ๋ฉ๋๋ค.
flutter pub run build_runner build๋ค์์ ๋ช ๋ น์ค์์ ์คํํ์ ๋ ๋์จ ์ถ๋ ฅ์ ๋๋ค. ํ๊ฒฝ์ ๋ฐ๋ผ ์กฐ๊ธ ๋ค๋ฅผ ์ ์์ต๋๋ค.
โ [mobx_getting_started]> flutter packages pub run build_runner build
[INFO] Generating build script...
[INFO] Generating build script completed, took 319ms
[INFO] Initializing inputs
[INFO] Reading cached asset graph...
[INFO] Reading cached asset graph completed, took 76ms
[INFO] Checking for updates since last build...
[INFO] Checking for updates since last build completed, took 705ms
[INFO] Running build...
[INFO] 1.1s elapsed, 0/3 actions completed.
[INFO] 6.7s elapsed, 2/3 actions completed.
[INFO] 7.7s elapsed, 3/3 actions completed.
[INFO] Running build completed, took 7.7s
[INFO] Caching finalized dependency graph...
[INFO] Caching finalized dependency graph completed, took 33ms
[INFO] Succeeded after 7.8s with 2 outputs (6 actions)INFO
watch ๋ชจ๋ ์ฌ์ฉํ๊ธฐ โ
์คํ ์ด๋ฅผ ์์ ํ ๋๋ง๋ค *.g.dart ํ์ผ์ ์๋์ผ๋ก ์์ฑํ๊ณ ์ถ๋ค๋ฉด ๋ค์ ๋ช
๋ น์ ์ฌ์ฉํฉ๋๋ค.
flutter pub run build_runner watch๊นจ๋ํ๊ฒ ๋ค์ ์์ํ๊ธฐ โ
๊ธฐ์กด ํ์ผ ๋๋ฌธ์ ์ด ๋ช
๋ น์ด ์ค๋ฅ๋ฅผ ์ผ์ผํฌ ์ ์์ต๋๋ค. ์ด์ ๋ฒ์ ์ build_runner๊ฐ ์์ฑํ ํ์ผ์ด ๋จ์ ์๋ ๊ฒฝ์ฐ๊ฐ ๋ํ์ ์
๋๋ค. ์ด๋ด ๋๋ ๋ค์ ํ๋๊ทธ๋ฅผ ์ถ๊ฐํด *.g.dart ํ์ผ์ ๋จผ์ ์ญ์ ํ ๋ค ๋ค์ ์์ฑํฉ๋๋ค.
flutter pub run build_runner watch --delete-conflicting-outputs์คํ ์ด๋ฅผ ์ฐ๊ฒฐํ๊ณ ์์ ฏ์ Observer ์ถ๊ฐํ๊ธฐ โ
์ด์ MobX ์คํ ์ด๋ฅผ ์์ ฏ์ ์ฐ๊ฒฐํ ์ฐจ๋ก์
๋๋ค. main.dart ํ์ผ์ ๋ด์ฉ์ ๋ค์ ์ฝ๋๋ก ๋ฐ๊ฟ๋๋ค.
import 'package:flutter/material.dart';
import 'package:flutter_mobx/flutter_mobx.dart';
import 'counter.dart'; // Import the Counter
final counter = Counter(); // Instantiate the store
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'MobX',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatelessWidget {
const MyHomePage();
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('MobX Counter'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
// Wrapping in the Observer will automatically re-render on changes to counter.value
Observer(
builder: (_) => Text(
'${counter.value}',
style: Theme.of(context).textTheme.headline4,
),
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: counter.increment,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}์ ์ฝ๋์๋ StatefulWidget์ด ํ๋๋ ์๋ค๋ ์ ์ ์ฃผ๋ชฉํ์ธ์. ์ํ๋ Counter ์คํ ์ด์ ์ ์ฅ๋๊ณ , Observer ์์ ฏ์ counter.value๋ฅผ ์ฝ์ด ์นด์ดํธ๋ฅผ ๋ ๋๋งํฉ๋๋ค. counter.value๋ฅผ ์ฝ๋ ๊ฒ๋ง์ผ๋ก Observer๊ฐ ์ถ์ ์ ์์ํ๋ฉฐ, ๊ฐ์ด ๋ฐ๋ ๋๋ง๋ค ๋ค์ ๋ ๋๋งํฉ๋๋ค.
์์ฑ์ ๋๋ค! โ
์ต์ข
๊ฒฐ๊ณผ๋ ์ฒ์ ๋ณด๋ ์นด์ดํฐ ์ฑ๊ณผ ๋๊ฐ์ต๋๋ค. FloatingActionButton์ ํญํ๋ฉด ์นด์ดํฐ๊ฐ ์ฆ๊ฐํ๊ณ ํ๋ฉด๋ ์๋์ผ๋ก ๊ฐฑ์ ๋ฉ๋๋ค.

๊ณ์ ๋๋ฌ๋ณด์ธ์! โ
๋ค๋ฅธ ์์ ๋ ์ดํด๋ณด๋ฉด์ MobX์ ์ต์ํด์ ธ ๋ณด์ธ์. MobX์ ํต์ฌ์ Observables, Actions, Reactions ์ธ ๊ฐ์ง์
๋๋ค ๐. ์ด ์ค Observables์ Actions๋ ์ด๋ฏธ ์ดํด๋ณด์์ต๋๋ค. Reactions๋ ๋ค๋ฅธ ์์ ์์ ๋ค๋ฃน๋๋ค.