Features

  • Lightweight state management for projects. Manage state using SuperState and notifications.
  • Create a SuperState and bind it in the State of a subtree to allow multiple States to share a single state.
  • SuperState can inject any content at any time.
  • States in the subtree can send notifications to SuperState, and all States can decide whether to listen.

Getting started

Installing

Add the following dependency to your pubspec.yaml

dependencies:
  super_state: latest_version

Importing

Import the package into your Dart code:

import 'package:super_state/super_state.dart';

Usage

Creating a SuperState

Define your own SuperState to manage shared state:

class MySuperState extends SuperState {
  int counter = 0;

  void increment() {
    counter++;
    setState();
  }
}

Providing SuperState

Wrap your widget tree with a SuperStateProvider to provide SuperState instances:

void main() {
  runApp(
    SuperStateProvider(
      states: [MySuperState()],
      child: MyApp(),
    ),
  );
}

Accessing SuperState

Use `State` extensions to bind and access `SuperState` in your widgets:

class MyWidget extends StatefulWidget {
  @override
  _MyWidgetState createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  @override
  void initState() {
    super.initState();
    // Bind the SuperState to enable updates
    bindSuperStateOf<MySuperState>();
  }

  @override
  Widget build(BuildContext context) {
    // Access the bound SuperState
    final myState = superStateOf<MySuperState>();

    return ElevatedButton(
      onPressed: () {
        myState?.increment();
      },
      child: Text('Increment'),
    );
  }
}

By binding the state, you ensure that your widget stays in sync with SuperState changes and can trigger updates when needed.

Listening to SuperState

Use SuperStateConsumer to rebuild widgets when SuperState changes:

class CounterWidget extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return SuperStateConsumer(
      builder: (context, setState, key) {
        final myState = context.superStateOf<MySuperState>();
        return Text('Counter: ${myState?.counter}');
      },
    );
  }
}

Sending Notifications

Send notifications to SuperState and handle them in your states:

class MySuperState extends SuperState {
  void handleNotification(String notificationName, Object? sender, dynamic other) {
    if (notificationName == 'increment') {
      increment();
    }
  }
}

context.postSuperStateNotificationOf<MySuperState>(
  notificationName: 'increment',
  sender: this,
);

Advanced Example

Here is a more advanced example demonstrating nested SuperStateProvider usage and state interaction:

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Demo',
      theme: ThemeData(colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple)),
      home: SuperStateProvider(
        states: [TopSuperState() + 0],
        key: ProviderId('Top'),
        child: SuperStateProvider(
          states: [
            ColorTopSuperState() + CellModels() + ConsoleModel(),
            RedSuperState(),
            BlueSuperState(),
          ],
          child: const MyHomePage(title: 'Flutter Demo Home Page'),
        ),
      ),
    );
  }
}

class MyHomePage extends StatefulWidget {
  const MyHomePage({super.key, required this.title});

  final String title;

  @override
  State<MyHomePage> createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        backgroundColor: Theme.of(context).colorScheme.inversePrimary,
        title: Text(widget.title),
      ),
      body: Column(
        children: [
          Expanded(child: ListPage()), // ListPage displays a list of items
          SizedBox(height: 80, child: ConsolePage()), // ConsolePage displays logs
        ],
      ),
      floatingActionButton: SuperStateConsumer(
        key: ProviderId('Top'),
        builder: (context, setState, key) {
          final superState = context.superStateOf<TopSuperState>(key: key);
          final count = superState?.getStateInfo<int>();
          return FloatingActionButton(
            onPressed: () {
              if (superState != null) {
                final nextCount = (superState.getStateInfo<int>() ?? 0) + 1;
                superState + nextCount; // Update TopSuperState's info

                superState.setState(); // Reset all states
              }
            },
            tooltip: 'Increment',
            child: Text(
              'Top $count',
              style: const TextStyle(fontSize: 14, color: Colors.purple),
            ),
          );
        },
      ),
    );
  }
}

super_state Demo

In this example:

  • SuperStateProvider is used to provide multiple SuperState instances.
  • SuperStateConsumer listens to TopSuperState and updates the floating action button.
  • Nested SuperStateProvider allows for scoped state management.

API Reference

  • SuperState: The core class for managing state and dependencies.
  • SuperStateProvider: Provides SuperState Go to definition instances to the widget tree.
  • SuperStateConsumer: Listens to SuperState changes and rebuilds widgets.
  • BuildContext Extensions: Simplifies accessing and interacting with SuperState.
  • State Extensions: Adds utility methods for State objects to interact with SuperState.

Conclusion

SuperState is a lightweight yet powerful state management tool suitable for small to medium-sized projects. With its simple API and flexible extensibility, you can quickly implement state management and communication between components.

For more details, visit the official documentation or check out the GitHub repository.

Libraries

super_state