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

GitHub 저장소zupat/lite_ref

lite_ref

Dart 및 Flutter용 가벼운 종속성 주입 라이브러리입니다.

lite_ref 프로젝트 이미지
스타
19
포크
3
최근 푸시(UTC)
2024. 11. 15.
프로젝트 상태
활성

원본 README

아래는 영문 원문 스냅샷입니다. 최신 내용은 GitHub에서 확인하세요.

Overview

Lite Ref is a lightweight dependency injection library for Dart and Flutter.

Installation

dart pub add lite_ref

Why Lite Ref?

  • Fast: Doesn't use hashmaps to store instances so it's faster than all other DI libraries.
  • Safe: Uses top level variables so it's impossible to get a NOT_FOUND error.
  • Lightweight: Has no dependencies.
  • Simple: Easy to learn with a small API surface

Scoped Refs

A ScopedRef is a reference that needs a build context to access its instance. This is an alternative to Provider for classes that don't rebuild widgets. eg: Controllers, Repositories, Services, etc.

  • Wrap your app or a subtree with a LiteRefScope:

    runApp(
      LiteRefScope(
        child: MyApp(),
      ),
    );
    
  • Create a ScopedRef.

    final settingsServiceRef = Ref.scoped((ctx) => SettingsService());
    
  • Access the instance in the current scope:

    This can be done in a widget by using settingsServiceRef.of(context) or settingsServiceRef(context).

    class SettingsPage extends StatelessWidget {
      const SettingsPage({super.key});
    
      @override
      Widget build(BuildContext context) {
        final settingsService = settingsServiceRef.of(context);
        return Text(settingsService.getThemeMode());
      }
    }
    
  • Override it for a subtree:

    You can override the instance for a subtree by using overrideWith. This is useful for testing. In the example below, all calls to settingsServiceRef.of(context) will return MockSettingsService.

    LiteRefScope(
      overrides: {
        settingsServiceRef.overrideWith((ctx) => MockSettingsService()),
      },
      child: MyApp(),
    ),
    

A ScopedFamilyRef is used when you need to create a unique instance for different keys. This is useful for creating multiple instances of the same class with different configurations.

  • Create a ScopedFamilyRef.

    final postControllerRef = Ref.scopedFamily((ctx, String key) {
      return PostController(key)..fetch();
    });
    
  • Access the instance in the current scope:

    This can be done in a widget by using postController.of(context, key) or postController(context, key).

    class PostsPage extends StatelessWidget {
      const PostsPage({required this.keys, super.key});
    
      final List<String> keys;
    
      @override
      Widget build(BuildContext context) {
        return ListView.builder(
          itemBuilder: (context, index) {
            final post = postControllerRef.of(context, keys[index]);
            return Text(post?.title ?? 'Loading...');
          },
        );
      }
    }
    
Disposal

When a ScopedRef provides a ChangeNotifier, ValueNotifier or a class that implements Disposable, it will automatically dispose the instance when all the widgets that have access to the instance are unmounted.

In the example below, the CounterController will be disposed when the CounterView is unmounted.

class CounterController extends ChangeNotifier {
  var _count = 0;
  int get count => _count;

  void increment() {
    _count++;
    notifyListeners();
  }

  void decrement() {
    _count--;
    notifyListeners();
  }
}

final countControllerRef = Ref.scoped((ctx) => CounterController());

class CounterView extends StatelessWidget {
  const CounterView({super.key});

  @override
  Widget build(BuildContext context) {
    final controller = countControllerRef.of(context);
    return ListenableBuilder(
      listenable: controller,
      builder: (context, snapshot) {
        return Text('${controller.count}');
      },
    );
  }
}
Click here for a flutter example with testing.

Global Singletons and Transients

  • Create a singleton:

    final dbRef = Ref.singleton(() => Database());
    
    assert(dbRef.instance == dbRef.instance);
    
  • Use it:

    final db = dbRef.instance; // or dbRef()
    
  • Override it (for testing):

    dbRef.overrideWith(() => MockDatabase());
    
  • Freeze it (disable overriding):

    // overrideWith is marked as @visibleForTesting so this isn't really necessary.
    dbRef.freeze();
    
  • Create a transient instance (always return new instance):

    final dbRef = Ref.transient(() => Database());
    
    assert(dbRef.instance != dbRef.instance);
    
  • Create a singleton asynchronously:

    final dbRef = Ref.asyncSingleton(() async => await Database.init());
    
  • Use it:

    final db = await dbRef.instance;
    
  • Use it synchronously:

    // only use this if you know the instance is already created
    final db = dbRef.assertInstance;
    
zupat GitHub avatar
GitHub 작성자

zupat ↗

언어DartShell

분류

프로젝트에 맞는 저장소를 선택하려면?

사용 목적에 따라 검색하고 개발 활동을 비교한 뒤 원본 저장소에서 요구 사항을 확인하세요.

  1. 이름, 작성자 또는 설명으로 검색하고 기술 주제로 범위를 좁힙니다.
  2. 스타, 포크, 최근 푸시를 함께 비교하세요. 스타는 관심의 지표이며 품질을 보장하지 않습니다.
  3. 사용하기 전에 GitHub에서 README, 라이선스, Issues를 확인하세요.

출처 및 관리

“A repository is the most basic element of GitHub.”

GitHub Docs — About repositories ↗