패키지, 저장소 및 앱 카테고리 검색

패키지 상세v0.2.1

syncx

syncx는 provider, bloc, riverpod을 영감으로 하여, 알림자와 반응형 UI 업데이트를 제공하는 가볍고 유연한 Flutter 상태 관리 라이브러리입니다.

AndroidiOSWebmacOSWindowsLinux
30일 다운로드
154
좋아요
3
Pub 점수
160

패키지 설치

flutter pub add syncx

패키지 개요

공개 정보를 바탕으로 생성한 선택 가이드입니다.

SyncX는 Flutter용 가볍고 유연한 상태 관리 라이브러리로, 노티파이어를 통해 반응형 UI 업데이트를 가능하게 합니다. Provider, Bloc, Riverpod에 영감을 받아 최소한의 부가 코드로 앱 상태를 간단하면서도 강력하게 관리할 수 있도록 제공합니다. SyncX는 종속성 주입을 지원하며 모든 주요 플랫폼과 원활하게 통합되어 확장 가능하고 유지보수가 쉬운 Flutter 애플리케이션에 적합합니다. 디자인은 명확성, 성능, 사용 편의성을 중시합니다.

사용 사례

  • 전역 앱 상태 관리
  • 상태 변경에 기반한 반응형 UI 업데이트
  • 대규모 앱에서의 의존성 주입
  • 복잡한 위젯에서 상태 로직 간소화
  • 여러 화면 간에 데이터 공유하기

주요 기능

  • 경량이고 빠름
  • 노티파이어 및 반응형 업데이트를 지원합니다
  • 크로스 플랫폼 호환성
  • 최소한의 보일러플레이트
  • 인기 있는 상태 관리 패턴에서 영감을 받음
  • 기존 플러터 프로젝트와의 간편한 통합

적합한 대상

  • Provider 또는 Bloc의 간단한 대안을 찾는 개발자
  • 효율적인 상태 공유가 필요한 프로젝트
  • 깨끗하고 확장 가능한 아키텍처를 원하는 팀
  • 다중 플랫폼을 대상으로 하는 Flutter 앱
  • 복잡성 없이 반응형 UI가 필요한 앱

고려 사항

  • 알림자 패턴에 익숙하지 않은 초보자에게는 학습 곡선이 필요할 수 있습니다
  • 성숙한 라이브러리에 비해 문서가 제한적
  • 매우 작은 앱보다는 중대형 앱에 더 적합합니다
  • 사용자 정의 없이 극도로 복잡한 상태 로직을 가진 앱에는 권장되지 않습니다

원본 README

연결된 소스 저장소의 README 원문 스냅샷입니다. 최신 내용은 저장소에서 확인하세요.

SyncX

Flutter state management made easy: SyncX is a lightweight, flexible state management solution for Flutter. It provides notifiers, builders, and consumers for reactive UI updates with minimal boilerplate. SyncX is designed for developers who want a simple, composable, and powerful way to manage state in their Flutter apps.

Note: The implementation and API of SyncX are inspired by popular state management solutions such as bloc, provider, and riverpod. Naming conventions and patterns are chosen to be developer-friendly, especially for those migrating from or familiar with these libraries.


Table of Contents


Why SyncX?

  • Simple and familiar API for Flutter state management.
  • Reactive UI updates with rebuild control: Widgets rebuild on state changes, with control over when they update.
  • Notifier pattern: Cleanly separates business logic from UI code.
  • Effortless async state handling: Easily manage loading, data, and error states.
  • Minimal boilerplate: Quick to set up and easy to integrate into any Flutter project.

Features

  • 🔄 Notifier-based state management: Simple, extendable notifiers for your app's state.
  • 🏗️ Builder widgets: Easily rebuild UI in response to state changes.
  • 👂 Listener widgets: React to state changes with side effects.
  • 🪶 Minimal boilerplate: Focus on your app logic, not on wiring up state.
  • ⚡ Async state support: Built-in support for loading, data, and error states in async flows.

Core Concepts & Usage

1. Create a Notifier

A Notifier holds and updates your state:


/// Extend [Notifier] for basic state management
/// update state and notify listeners using [setState].
class CounterNotifier extends Notifier<int> {
  /// Creates a [CounterNotifier] with an initial state of 0.
  CounterNotifier() : super(0);

  /// Optionally override [onInit] to perform initialization logic when the notifier is first created.
  ///
  /// This method is called automatically once the instance is created.
  /// Use it to initialize resources or start listeners if needed.
  @override
  void onInit(){
    // doSomething...
  }

  /// Increments the counter by 1 and notifies listeners.
  ///
  /// Use [setState] to update the state and notify any listening widgets.
  ///
  /// [setState] also accepts two optional parameters:
  ///   - [forced] (default: false): Forces the state update even if the value hasn't changed, useful for mutating iterable state.
  ///   - [notify] (default: true): Controls whether listeners are notified and the UI is rebuilt.
  void increment() => setState(state + 1);
}

For async state (loading/data/error):

/// Extend [AsyncNotifier] to handle async operations such as network calls 
/// to handle loading, data, and error states using [AsyncState].
class GreetingAsyncNotifier extends AsyncNotifier<String> {
  /// Creates a [GreetingAsyncNotifier] with an initial state.
  GreetingAsyncNotifier() : super();

  /// Called when the notifier is first initialized.
  ///
  /// This method is called automatically once the instance is created.
  ///
  /// It simulates a network call by delaying for 2 seconds.
  /// If the operation is successful, it returns an [AsyncState.data] with a greeting message.
  /// Otherwise, it returns an [AsyncState.error] with an error message.
  @override
  Future<AsyncState<String>> onInit() async {
    // Consider this as a Network call
    await Future.delayed(const Duration(seconds: 2));
    final bool isSuccess = true; // Set to false to simulate error
    if (isSuccess) {
      return const AsyncState.data('Hello from AsyncNotifier!');
    }
    return const AsyncState.error('Failed to load greeting');
  }

  /// Updates the state by simulating an asynchronous operation.
  ///
  /// This method demonstrates how to manually set the state to loading,
  /// perform an async task, and then update the state to either data or error.
  ///
  /// - Sets the state to loading before starting the async operation.
  /// - If successful, sets the state to data with a success message.
  /// - If failed, sets the state to error with an error object and message.
  Future<void> updateState() async {
    setState(state.toLoading());
    // Consider this as a Network call
    await Future.delayed(const Duration(seconds: 2));
    final bool isSuccess = true; // Set to false to simulate error
    if (isSuccess) {
      return setState(state.toData('Success'));
    }

    // Replace 'errorObject' with your actual error object as needed
    return setState(
      state.toError('..errorObject', message: 'Network call failed'),
    );
  }
}
2. Register the Notifier

Register your notifier at the root of your widget tree:

NotifierRegister(
  create: (context) => CounterNotifier(),
  child: MyApp(),
)

You can nest registers for multiple notifiers:

NotifierRegister(
  create: (context) => CounterNotifier(),
  child: NotifierRegister(
    create: (context) => GreetingAsyncNotifier(),
    child: MyApp(),
  ),
)
3. Consume State with Builders & Listeners

Rebuild UI on State Change:

NotifierBuilder<CounterNotifier, int>(
  builder: (context, count) => Text('Count: $count'),
)

Control rebuilds:

NotifierBuilder<CounterNotifier, int>(
  buildWhen: (prev, curr) => prev != curr,
  builder: (context, count) => Text('Count: $count'),
)

Listen for Side Effects:

NotifierListener<CounterNotifier, int>(
  listenWhen: (prev, curr) => curr % 2 == 0,
  listener: (count) => print('Count is even: $count'),
  child: MyWidget(),
)

Combine Build and Listen:

NotifierConsumer<CounterNotifier, int>(
  builder: (context, count) => Text('Count: $count'),
  listener: (count) => print('Count changed: $count'),
)

Async State Handling:

SyncX provides specialized widgets for handling asynchronous state:

  • AsyncNotifierBuilder – a wrapper over NotifierBuilder for async state, providing a convenient API for loading, data, and error UI.
  • AsyncNotifierConsumer – combines building and listening for side effects in async flows.
  • AsyncNotifierListener – listens for async state changes and triggers side effects without rebuilding the UI.

Direct usage with builder:

AsyncNotifierBuilder<GreetingAsyncNotifier, String>(
  builder: (context, state) {
    return state.when(
      loading: () => const CircularProgressIndicator(),
      data: (greeting) => Text(greeting),
      error: (error) => Text('Error: \\${error.message}'),
    );
  },
)

Convenient usage with .withData:

AsyncNotifierBuilder<GreetingAsyncNotifier, String>.withData(
  loadingBuilder: () => CircularProgressIndicator(),
  dataBuilder: (greeting) => Text(greeting),
  errorBuilder: (error) => Text('Error: \\${error.message}'),
)

You can use AsyncNotifierConsumer and AsyncNotifierListener similarly to handle both UI and side effects for async state.

4. Invoking Notifier Methods

To invoke a method inside your notifier (for example, to increment the counter), use the context extension or provider pattern in your widget. Here’s how you can call a notifier method from a button press:

ElevatedButton(
  onPressed: () => context.read<CounterNotifier>().increment(),
  child: const Text('Increment'),
)

This will call the increment method on your CounterNotifier and update the state accordingly.


Bad Practices / Don’ts
  • Don’t: Do not call the notifier’s onInit manually from builder, consumer, or listener onInit callbacks. This will result in duplicate initialization and unexpected behavior. The onInit method inside your notifier will be called automatically once the notifier instance is created. You do not need to call it yourself.

    Incorrect usage example:

    NotifierBuilder<Notifier, State>(
      // Do NOT do this:
      onInit: (notifier) => notifier.onInit(),
      // Do this if you need to call your own custom initialization logic when the widget is created:
      onInit: (notifier) => notifier.doSomethingElse(),
      builder: (context, state) => Text('State: $state'),
    )
    

Usage Patterns

  • Rebuild UI on State Change: Use NotifierBuilder with buildWhen for fine-grained rebuild control.
  • Listen for Side Effects: Use NotifierListener with listenWhen for side-effect logic.
  • Combine Build and Listen: Use NotifierConsumer for both UI and side effects.
  • Async State Handling: Use AsyncNotifier and AsyncState for loading, data, and error flows.

Future Plans

  • Built-in stream support in notifiers for easy loading and error state management.
  • Top-level observer support to monitor state changes across the app.
  • Migrate dependency injection (DI) from provider to a custom DI implementation for more flexibility and control.

Contributing

Contributions are welcome! Please open issues or pull requests on GitHub.


License

This project is licensed under the MIT License.


If you have questions or need help, please open an issue or start a discussion on GitHub.

카테고리

의존성

의존성 목록 1 개

소스 저장소

이 패키지를 사용하는 프로젝트

아직 데이터가 없습니다.