š LiveBloc
LiveBloc
is a bloc that syncs its state across devices in real-time. It works
by
- Fetching the most recent state from the server.
- Subscribing to the server to receive events from all other devices.
- Writing the updated state to the server (only from the device that made the change).
Step 1: Extend LiveBloc
Section titled āStep 1: Extend LiveBlocāTo use LiveBloc
, first, simply extend it instead of Bloc
.
import 'package:blocsync/blocsync.dart';
class CounterBloc extends LiveBloc<CounterEvent, int> { CounterBloc() : super(0) { on<Increment>((event, emit) => emit(state + 1)); on<Decrement>((event, emit) => emit(state - 1)); }}
Step 2: Implement State Serialization
Section titled āStep 2: Implement State SerializationāAdd toJson
and fromJson
methods to transform your state to and from JSON:
class CounterBloc extends SyncedBloc<CounterEvent, int> { CounterBloc() : super(0) { on<Increment>((event, emit) => emit(state + 1)); on<Decrement>((event, emit) => emit(state - 1)); }
@override int fromJson(Map<String, dynamic> json) => json['value'] as int;
@override Map<String, dynamic>? toJson(int state) => {'value': state};}
Step 3: Add LiveEvent mixin to your event class
Section titled āStep 3: Add LiveEvent mixin to your event classāabstract class CounterEvent with LiveEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
Step 4: Add event serialization
Section titled āStep 4: Add event serializationāAdd eventFromJson
and eventToJson
methods to transform your events to and from JSON.
class CounterBloc extends SyncedBloc<CounterEvent, int> { CounterBloc() : super(0) { on<Increment>((event, emit) => emit(state + 1)); on<Decrement>((event, emit) => emit(state - 1)); }
@override Map<String, dynamic>? eventToJson(CounterEvent event) { switch (event) { case Increment(): return {'type': 'increment'}; case Decrement(): return {'type': 'decrement'}; } return null; }
@override CounterEvent? eventFromJson(Map<String, dynamic> json) { final type = json['type'] as String; switch (type) { case 'increment': return Increment(); case 'decrement': return Decrement(); } return null; }}
Thatās it! š Your bloc will now sync events across devices in real-time.
Complete Example
Section titled āComplete Exampleāimport 'package:blocsync/blocsync.dart';
class CounterBloc extends LiveBloc<CounterEvent, int> { CounterBloc() : super(0) { on<Increment>((event, emit) => emit(state + 1)); on<Decrement>((event, emit) => emit(state - 1)); }
@override int fromJson(Map<String, dynamic> json) => json['value'] as int;
@override Map<String, dynamic>? toJson(int state) => {'value': state};
@override CounterEvent? eventFromJson(Map<String, dynamic> json) { final type = json['type'] as String; switch (type) { case 'increment': return Increment(); case 'decrement': return Decrement(); } return null; }
@override Map<String, dynamic>? eventToJson(CounterEvent event) { switch (event) { case Increment(): return {'type': 'increment'}; case Decrement(): return {'type': 'decrement'}; } return null; }}
abstract class CounterEvent with LiveEvent {}
class Increment extends CounterEvent {}
class Decrement extends CounterEvent {}
Compatibility with Other Blocsync Features
Section titled āCompatibility with Other Blocsync FeaturesāLiveBloc
s can be made private and partitioned just like SyncedBloc
s. For
more information, see Private Blocs and
Partitioned Blocs.
Why Sync Events instead of States?
Section titled āWhy Sync Events instead of States?āA lot of debate went into this decision. In the end, the decision came down to some future plans.
Primarily, we plan to support SharedBloc
s soon, which will allow you to sync
states across multiple users. However, this will require much more sophisticated
security than private blocs. Some questions we asked were:
- How to we allow certain users to read state and others manipulate it?
- How do we allow certain users to manipulate state in some ways, but others manipulate it in different ways?
We realized that we could restrict userās abilities to send events, and that would restrict their ability to manipulate state.
It does have some drawbacks. It means
- We canāt support a
LiveCubit
- States are not guaranteed to be in sync across devices perfectly. If a user misses an event, the state will be out of sync.
Weāre open to feedback on this decision. If you have feedback, please let us know in the GitHub Discussions.