LIVO 차세대 Flutter 상태 관리

발행: (2026년 2월 23일 오후 07:47 GMT+9)
6 분 소요
원문: Dev.to

Source: Dev.to

Flutter는 훌륭하지만, 상태 관리는 금방 복잡해질 수 있습니다. 작은 프로젝트에서는 setState를, 큰 앱에서는 Provider, Riverpod, BLoC 등을 사용했을 겁니다—하지만 각각 장단점이 있습니다.

Note: 이 이야기는 원래 reactive_orm에 관한 것이었으며, 현재는 더 이상 사용되지 않습니다. 그 진화된 형태가 LIVO입니다. LIVO는 개선된 명명법, 문서화, 장기 지원과 함께 반응형 객체‑관계 상태‑관리 접근 방식을 지속합니다.

LIVO란?

Enter LIVO: Flutter용 가볍고 반응형인 ORM‑스타일 상태‑관리 라이브러리입니다.
모델 속성이 변경될 때 UI가 자동으로 반응하도록 해줍니다 — 스트림, ChangeNotifier, 혹은 보일러플레이트가 필요 없습니다.

LIVO와 함께 얻는 것

  • 객체‑별 및 필드‑별 반응성
  • 중첩 및 공유 모델
  • 다 → 일 및 다 ↔ 다 관계
  • 최소한의 보일러플레이트, 순수 Dart 모델

LIVO 작동 예시

  • Object‑wise: 어떤 필드든 업데이트하고 전체 위젯을 재구성합니다
  • Field‑wise: 선택된 필드에 대해서만 위젯을 재구성합니다
  • Many → One: 여러 모델이 하나의 옵저버에 공급됩니다
  • Many ↔ Many: 공유 모델이 여러 부모에 반영됩니다

Getting Started

프로젝트에 LIVO를 추가하세요:

dependencies:
  livo: ^

1️⃣ Reactive Model 만들기

import 'package:livo/livo.dart';

class Task extends ReactiveModel {
  String _title;
  bool _completed = false;
  String _status = "Idle";

  Task({required String title}) : _title = title;

  String get title => _title;
  set title(String value) {
    if (_title != value) {
      _title = value;
      notifyListeners(#title); // ✅ Symbol‑based
    }
  }

  bool get completed => _completed;
  set completed(bool value) {
    if (_completed != value) {
      _completed = value;
      notifyListeners(#completed);
    }
  }

  String get status => _status;
  set status(String value) {
    if (_status != value) {
      _status = value;
      notifyListeners(#status);
    }
  }
}

✅ 이것은 순수 Dart 코드입니다. LIVO가 필드가 변경될 때 위젯에 알림을 자동으로 처리합니다.

2️⃣ 객체 단위 리액티비티

final objectWise = Task(title: "Object-wise Reactivity");

ReactiveBuilder(
  model: objectWise,
  builder: (task) {
    return ListTile(
      title: Text(task.title),
      subtitle: Text(task.status),
      trailing: Checkbox(
        value: task.completed,
        onChanged: (v) => task.completed = v!,
      ),
    );
  },
);

체크박스를 클릭하면 전체 위젯이 다시 빌드됩니다.

3️⃣ 필드 단위 리액티비티 (최적화)

final fieldWise = Task(title: "Field-wise Reactivity");

ReactiveBuilder(
  model: fieldWise,
  fields: [#completed, #status],
  builder: (task) {
    return ListTile(
      title: Text(task.title),
      subtitle: Text(task.status),
      trailing: Checkbox(
        value: task.completed,
        onChanged: (v) => task.completed = v!,
      ),
    );
  },
);

completed 또는 status가 변경될 때만 위젯이 다시 빌드되고, 다른 필드는 무시됩니다.

4️⃣ Many → One (집계)

class Dashboard extends ReactiveModel {
  final List sources;

  Dashboard(this.sources) {
    for (final task in sources) {
      addNested(task); // listen to many
    }
  }
}

final manyA = Task(title: "Task A");
final manyB = Task(title: "Task B");
final dashboard = Dashboard([manyA, manyB]);

ReactiveBuilder(
  model: dashboard,
  builder: () => Column(
    children: [
      Text("A: ${manyA.completed}"),
      Text("B: ${manyB.completed}"),
    ],
  ),
);

manyA 또는 manyB가 업데이트되면 대시보드 위젯이 자동으로 다시 빌드됩니다.

5️⃣ Many ↔ Many (공유 모델)

class Group extends ReactiveModel {
  final String name;
  final List tasks;

  Group({required this.name, required this.tasks}) {
    for (final task in tasks) addNested(task);
  }
}

final group1 = Group(name: "Group 1", tasks: [objectWise, fieldWise]);
final group2 = Group(name: "Group 2", tasks: [fieldWise, manyA]);

ReactiveBuilder(
  model: group1,
  builder: (g) => Column(
    children: g.tasks
        .map((t) => Text("• ${t.title}${t.completed}"))
        .toList(),
  ),
);

✅ 작업을 업데이트하면 해당 작업을 포함하고 있는 모든 그룹에 자동으로 반영됩니다.

How LIVO Works

  • 모델은 ReactiveModel을 확장합니다
  • 필드 세터는 값이 변경될 때마다 notifyListeners(#field)를 호출합니다
  • ReactiveBuilder 위젯은 전체 객체 또는 특정 필드 중 하나를 구독합니다
  • 중첩된 모델은 변경 사항을 자동으로 상위로 전파합니다
  • 스트림이 없습니다. 수동 연결이 없습니다. 모든 것이 안전하고 효율적으로 업데이트됩니다.

Why LIVO

  • 최소한의 보일러플레이트로 깔끔한 Dart 모델
  • 최적화된 성능을 위한 세밀한 반응성
  • 더 쉬운 앱 설계를 위한 ORM‑스타일 사고 모델
  • 단일 필드, 중첩 모델, 공유 모델 모두에서 원활하게 작동

링크

독자를 위한 팁

작게 시작하세요: 빠른 프로토타이핑을 위해 객체‑단위 반응성을 사용하세요. 앱이 성장함에 따라 효율성을 위해 필드‑단위 또는 중첩 모델로 전환하세요.

LIVO는 Flutter 상태 관리를 직관적이고 재미있게 만들어 줍니다 — 성능을 희생하지 않으면서.

0 조회
Back to Blog

관련 글

더 보기 »