[Flutter] 상태관리 Signals

Noah·2024년 7월 7일
0

Flutter

목록 보기
6/11
post-thumbnail

Flutter에서 사용할 수 있는 상태관리 중 하나인 Signal을 소개한다.

Signal은 새로운 것이 아니며 오랫동안 존재해왔다.
javascript 프레임워크에는 핵심 라이브러리의 일부로 포함되어 있다.

Signals 기능

미세한 반응성

  • Preact 신호를 기반으로 하며 종속성을 자동으로 추적하고 더 이상 필요하지 않을 때 해제하는 세분화된 반응성 시스템을 제공한다.

lazy

  • signals은 읽을 때만 값을 계산한다. 신호를 읽지 않으면 계산되지 않는다.

효과적인 렌더링

  • 위젯은 업데이트가 필요한 위젯 트리 부분과 마운트된 부분만 표시하여 다시 구축할 수 있다.

100% Dart Native

  • Dart JS(HTML), Shelf Server, CLI(및 기본), VM, Flutter(웹, 모바일 및 데스크톱)를 지원합니다. signals은 모든 Dart 프로젝트에서 사용할 수 있다.

심플하고 유연한 API

  • 모든 앱은 다르며 signals은 다양한 방식으로 구성될 수 있다. 따라야 할 몇 가지 규칙이 있지만 API 표면이 작아 쉽게 적용할 수 있다.

Signals 쓰는 이유

너무 복잡하고 비대한 상태관리들

  • Riverpod, Bloc, Getx 등의 상태관리들은 너무 많은 기능을 제공하여, 높은 Learning curve가 있다.

심플하고 필요한 기능만 제공

  • 상태관리에 필요한 기능만을 제공하기 때문에 어떤 서비스든 간단하고, 유연하게 적용할 수 있다.
  • Bloc과 같이 Architecture를 강요하지 않는다.

가독성 좋은 코드

// 생성
final counter = signal(0);
// 사용
Watch((context) => Text('Counter: $counter'))

Signals

import 'package:signals/signals.dart';

final counter = signal(0);

// Read value from signal, logs: 0
print(counter.value);

// Write to a signal
counter.value = 1;

.value

final counter = signal(0);

effect(() {
  print(counter.value);
});

counter.value = 1;

.previousValue

final counter = signal(0);

effect(() {
  print('Current value: ${counter.value}');
  print('Previous value: ${counter.previousValue}');
});

counter.value = 1;

Force Update

final counter = signal(0);
counter.set(1, force: true);

Disposing

final s = signal(0, autoDispose: true);
s.onDispose(() => print('Signal destroyed'));
final dispose = s.subscribe((_) {});
dispose();
final value = s.value; // 0
// prints: Signal destroyed
final s = signal(0);
s.dispose();
final c = computed(() => s.value);
// c will not react to changes in s
final s = signal(0);
print(s.disposed); // false
s.dispose();
print(s.disposed); // true

Computed

import 'package:signals/signals.dart';

final name = signal("Jane");
final surname = signal("Doe");

final fullName = computed(() => name.value + " " + surname.value);

// Logs: "Jane Doe"
print(fullName.value);

// Updates flow through computed, but only if someone
// subscribes to it. More on that later.
name.value = "John";
// Logs: "John Doe"
print(fullName.value);

Effect

import 'package:signals/signals.dart';

final name = signal("Jane");
final surname = signal("Doe");
final fullName = computed(() => name.value + " " + surname.value);

// Logs: "Jane Doe"
effect(() => print(fullName.value));

// Updating one of its dependencies will automatically trigger
// the effect above, and will print "John Doe" to the console.
name.value = "John";

Batch

import 'package:signals/signals.dart';

final name = signal("Jane");
final surname = signal("Doe");
final fullName = computed(() => name.value + " " + surname.value);

// Logs: "Jane Doe"
effect(() => print(fullName.value));

// Combines both signal writes into one update. Once the callback
// returns the `effect` will trigger and we'll log "Foo Bar"
batch(() {
  name.value = "Foo";
  surname.value = "Bar";
});

참조

https://dartsignals.dev/
https://pub.dev/packages/signals

profile
Flutter Specialist

0개의 댓글