one_store 0.0.1 copy "one_store: ^0.0.1" to clipboard
one_store: ^0.0.1 copied to clipboard

A lightweight state management + persistence plugin.

OneStore #

A lightweight, zero-boilerplate state persistence library for Flutter. It lets you persist any model to disk with JSON, reactively listen to changes, and rebuild widgets only when selected values change.

OneStore is ideal for apps needing persistent local state without complex databases, streams, or bloated architecture.


๐Ÿš€ Features #

  • Persistent Store โ€“ Automatically save/load JSON models to local storage.
  • Selector-Based Rebuilds โ€“ Widgets rebuild only when the selected slice of state changes.
  • Simple API โ€“ Set state, load state, and select data.
  • No Streams Required โ€“ Powered by ValueNotifier.
  • Safe Writes โ€“ Built-in async write locking prevents file corruption.
  • Fully Testable โ€“ Includes widget-friendly selector components and predictable behavior.

๐Ÿ“ฆ Installation #

Add the package to your pubspec.yaml:

dependencies:
  one_store: ^1.0.0

Then import it:

import 'package:one_store/one_store.dart';

๐Ÿง  How It Works #

You define a model that extends Persistable<T>:

  • toJson() converts the model to a serializable map.
  • fromString() rebuilds the model from a JSON string.

OneStore<T> wraps this model and:

  • Loads saved JSON on startup
  • Provides reactive selectors
  • Saves updated state on widget disposal / state changes

๐Ÿ“ Example: Create a Persistable Model #

class CounterState extends Persistable<CounterState> {
  final int count;
  CounterState(this.count);

  @override
  Map<String, dynamic> toJson() => {
    'count': count,
  };

  @override
  CounterState fromString(String jsonString) {
    final decoded = jsonDecode(jsonString);
    return CounterState(decoded['count']);
  }
}

๐Ÿ—ƒ๏ธ Using OneStore #

Initialize the store #

't load automatically โ€” you control when to load.

final store = OneStore(CounterState(0));
await store.load();

Update state #

store.setState(CounterState(store.state!.count + 1));

Read part of the state #

final count = store.getState((s) => s?.count ?? 0);

๐Ÿ” Selector-Based UI Updates #

OneStore provides createComponent() which only rebuilds when the selected value changes.

store.createComponent<int>(
  (state) => state?.count ?? 0,
  (context, count) => Text('Count: $count'),
)

This ensures:

  • No full widget rebuilds
  • No unnecessary UI updates
  • Better performance for large reactive states

๐Ÿ’พ Persistence Behavior #

The library saves the JSON string to a single file:

local_data.txt

Includes: #

  • Async write locking โ†’ avoids corrupted files
  • Automatic loading via store.load()

Excludes (on purpose): #

  • No background automatic saving
  • No file watching

If you want automatic debounced saving, you can add it manually.


๐Ÿงช Testing #

Benchmark save/load #

test('Save/load benchmark', () async {
  final store = OneStore(BigState(List.generate(100000, (i) => i)));
  await store.load();

  final sw = Stopwatch()..start();
  await store.state!.saveStringLocally(store.state.toString());
  sw.stop();

  print('Save took: ${sw.elapsedMilliseconds} ms');
});

Selector build frequency #

testWidgets('Selector test', (tester) async {
  int builds = 0;
  final store = OneStore(CounterState(0));
  await store.load();

  await tester.pumpWidget(
    store.createComponent((s) => s?.count ?? 0, (c, v) {
      builds++;
      return Text('$v');
    })
  );

  for (var i = 0; i < 10; i++) {
    store.setState(CounterState(i));
    await tester.pump();
  }

  expect(builds <= 15, true);
});

๐Ÿ›ก๏ธ Thread-Safe Writing #

OneStore includes a simple async lock:

static bool _isWriting = false;

It prevents overlapping writes that can corrupt JSON.

If you need:

  • Atomic writes
  • Multi-file support
  • Encrypted storage
  • Isolate-based serialization

โ†’ Open an issue, or request a feature.


๐Ÿ“‚ File Storage Path #

By default, files are stored at:

project root โ†’ local_data.txt

Inside a real Flutter app, this resolves to the app sandbox directory.

You can also override this behavior if needed.


๐Ÿ”ง Advanced Usage #

Custom File Names #

You can override save/load paths inside your model.

Debounced Auto-Save #

Call saveStringLocally() from inside setState() if you want live syncing.

Split Stores #

You can maintain multiple OneStores for different slices of state.


๐Ÿค Contributing #

PRs and suggestions are welcome! Feel free to open an issue for bugs, feature requests, or improvements.


๐Ÿ“œ License #

MIT License โ€” free to use in commercial and open-source projects.


โค๏ธ Support #

If you like this package, please give it a โญ on GitHub and pub.dev!

0
likes
130
points
7
downloads

Documentation

API reference

Publisher

unverified uploader

Weekly Downloads

A lightweight state management + persistence plugin.

License

MIT (license)

Dependencies

flutter

More

Packages that depend on one_store