bloc_lens 0.2.0 copy "bloc_lens: ^0.2.0" to clipboard
bloc_lens: ^0.2.0 copied to clipboard

Lenses and extensions based on lens_base, made for the bloc package.

Functional lenses for Dart & BLoC #

To read the basic documentation & the rationale, please visit the lens_base package.

This package provides a set of BLoC-specific classes and extensions.

Usage #

Let's say you have a BLoC with many properties, and you want an easy way to modify these values independently. Normally, you would have to create separate methods for each property, like this:

class SettingsCubit extends Cubit<SettingsState> {
  SettingsCubit() : super(SettingsState());

  void setScaling(double scaling) {
    emit(state.copyWith(scaling: scaling));
  }

  void setHapticFeedback(bool hapticFeedback) {
    emit(state.copyWith(hapticFeedback: hapticFeedback));
  }

  void setThemeMode(ThemeMode themeMode) {
    emit(state.copyWith(themeMode: themeMode));
  }

  void setLocale(Locale locale) {
    emit(state.copyWith(locale: locale));
  }

  void setFontSize(double fontSize) {
    emit(state.copyWith(fontSize: fontSize));
  }
}

class SettingsState {
  const SettingsState({
    required this.scaling,
    required this.hapticFeedback,
    required this.themeMode,
    required this.locale,
    required this.fontSize,
  });

  final double scaling;
  final bool hapticFeedback;
  final ThemeMode themeMode;
  final Locale locale;
  final double fontSize;
}

But that separates the getter and setter for each property, which forces you to pass around the current value, the way to change it, and possibly some more information (like the list of allowed values, or the allowed range). With lenses, you have one object that fully manages the value, together with its constraints:

โŒ Without lensesโœ… With lenses
class MySlider extends StatelessWidget {
  const MySlider({
    super.key,
    required this.value,
    required this.onChanged,
    required this.min,
    required this.max,
  });
  
  final double value;
  final ValueChanged<double> onChanged;
  final double min;
  final double max;

  @override
  Widget build(BuildContext context) {
    ...
  }
}
class MySlider extends StatelessWidget {
  const MySlider({
    super.key,
    required this.lens,
  });
  
  final NumberLens<double> lens;

  @override
  Widget build(BuildContext context) {
    ...
  }
}

To define lenses inside BLoCs, you can use the extensions provided by this package:

class SettingsCubit extends Cubit<SettingsState> {
  SettingsCubit() : super(SettingsState());

  late final scaling = numberLens(
    get: () => state.scaling,
    set: (value) => state.copyWith(scaling: value),
    min: 0.5,
    max: 2.0,
    increment: 0.1,
  );

  late final themeMode = enumLens(
    get: () => state.themeMode,
    set: (value) => state.copyWith(themeMode: value),
    values: ThemeMode.values,
  );
  
  ...
}

You can then use these inside your widgets:

Widget build(BuildContext context) {
  final cubit = context.watch<SettingsCubit>();

  return MySlider(
    lens: cubit.scaling,
  );
}

If you're also using flutter_hooks, you can include in your project a hook that combines finding the bloc and listening to the specific changes:

@optionalTypeArgs
L useBlocLens<B extends BlocBase<S>, S, L extends BlocLens<S, T>, T>(
  L Function(B cubit) lensGetter, {
  bool listen = true,
}) {
  final cubit = useContext().read<B>();
  final lens = lensGetter(cubit);
  useStream(
    listen ? cubit.stream.map((_) => lens.get()).distinct() : null,
  );
  return lens;
}
Widget build(BuildContext context) {
  final scaling = useBlocLens((SettingsCubit cubit) => cubit.scaling);

  return MySlider(
    lens: scaling,
  );
}

Please note, that this hook is not provided out-of-the-box in the package to keep the dependencies Flutter-less.

For an example of how to use lenses in a sample Flutter app, check out the example app.


๐Ÿงช Experimental #

If you want to preview an even easier way of using lenses inside BLoCs without any boilerplate, check out the bloc_lens_macros package.


LeanCode

Built with โ˜•๏ธ by LeanCode

8
likes
150
pub points
64%
popularity

Publisher

verified publisherleancode.co

Lenses and extensions based on lens_base, made for the bloc package.

Homepage
Repository (GitHub)
View/report issues

Topics

#bloc #dart #state #state-management

Documentation

API reference

License

Apache-2.0 (LICENSE)

Dependencies

bloc, lens_base, meta

More

Packages that depend on bloc_lens