iState - Lightweight Flutter State Management, Business Logic

A lightweight, efficient state management solution for Flutter applications with automatic lifecycle management and hot reload preservation.

๐ŸŒŸ Features

  • Automatic Lifecycle Management: States are created, registered, and disposed automatically
  • Hot Reload Preservation: Automatic state persistence during development
  • Global State Access: Convenient state<T>() function for state interaction
  • Type Safety: Compile-time type checking with generic parameters
  • Performance Optimization: Selective UI rebuilds with StateBuilder
  • No Context Propagation: Access states without passing context through widget trees

๐Ÿš€ Installation

Add to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  istate: ^1.0.0

๐Ÿ“– Core Concepts

IStatelessWidget

Extend IStatelessWidget instead of StatelessWidget to manage states:

class MyApp extends IStatelessWidget {
  @override
  List<IState> get states => [CounterState()];

  @override
  Widget build(BuildContext context) {
    return MaterialApp(home: HomeScreen());
  }
}

IState

Create custom states by extending IState<T>:

class CounterState extends IState<int> {
  CounterState() : super(0); // restorationId is auto-generated

  void increment() => set(value + 1);
  void decrement() => set(value - 1);
  void reset() => set(0);
}

StateBuilder

Use StateBuilder for reactive UI updates:

StateBuilder<CounterState>(
  builder: (state) => Text('Count: ${state.value}'),
)

Global Access

Access states globally using the state<T>() function:

onPressed: () => state<CounterState>().increment(),

๐Ÿ”ง Usage Guide

1. Create State Classes

class UserState extends IState<User> {
  UserState() : super(User.empty());

  void login(User user) => set(user);
  void logout() => set(User.empty());
  bool get isLoggedIn => value.id.isNotEmpty;
}

2. Declare States in Widgets

class HomeScreen extends IStatelessWidget {
  @override
  List<IState> get states => [CounterState(), UserState()];

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CounterDisplay(),
      floatingActionButton: IncrementButton(),
    );
  }
}

3. Build Reactive UI

class CounterDisplay extends IStatelessWidget {
  @override
  Widget build(BuildContext context) {
    return StateBuilder<CounterState>(
      builder: (state) => Text('Count: ${state.value}'),
    );
  }
}

4. Access States Globally

class IncrementButton extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return FloatingActionButton(
      onPressed: () => state<CounterState>().increment(),
      child: Icon(Icons.add),
    );
  }
}

๐Ÿ”ฅ Hot Reload Preservation

States automatically preserve their values during hot reload:

class CounterState extends IState<int> {
  CounterState() : super(0); // Auto-generated restoration ID
  // Or explicitly: super(0, restorationId: 'my_counter');

  void increment() => set(value + 1);
}

During development, counter values persist across hot reload sessions without any additional configuration.

๐Ÿ—๏ธ Architecture

IStatelessWidget
โ”œโ”€โ”€ _IStateProvider (lifecycle management)
โ”‚   โ”œโ”€โ”€ _IStateModel (state distribution)
โ”‚   โ””โ”€โ”€ _GlobalStateManager (global access)
โ”œโ”€โ”€ IState (individual states)
โ””โ”€โ”€ StateBuilder (reactive UI)

๐ŸŽฏ Advanced Patterns

Complex State Management

class TodoListState extends IState<List<Todo>> {
  TodoListState() : super([]);

  void addTodo(Todo todo) => set([...value, todo]);
  void removeTodo(Todo todo) => set(value.where((t) => t.id != todo.id).toList());
  int get completedCount => value.where((todo) => todo.completed).length;
}

State Composition

class DashboardWidget extends IStatelessWidget {
  @override
  List<IState> get states => [UserState(), NotificationState()];

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        StateBuilder<UserState>(
          builder: (userState) => UserHeader(user: userState.value),
        ),
        StateBuilder<NotificationState>(
          builder: (notificationState) => NotificationBadge(
            count: notificationState.unreadCount,
          ),
        ),
      ],
    );
  }
}

โšก Performance Optimization

Selective Rebuilding

// Efficient: Only rebuilds when specific state changes
Column(
  children: [
    StateBuilder<CounterState>(
      builder: (state) => Text('Count: ${state.value}'),
    ),
    StateBuilder<UserState>(
      builder: (state) => Text('User: ${state.value.name}'),
    ),
  ],
)

Efficient State Updates

// Good: Batch updates
void updateProfile(String name, String email) {
  set(value.copyWith(name: name, email: email));
}

// Avoid: Multiple sequential updates
void updateProfileBad(String name, String email) {
  set(value.copyWith(name: name));    // Triggers rebuild
  set(value.copyWith(email: email));  // Triggers rebuild
}

๐Ÿงช Testing

Unit Testing States

void main() {
  test('CounterState increments correctly', () {
    final counter = CounterState();
    expect(counter.value, 0);

    counter.increment();
    expect(counter.value, 1);
  });
}

Widget Testing

testWidgets('Counter updates UI', (tester) async {
  await tester.pumpWidget(MyApp());

  expect(find.text('Count: 0'), findsOneWidget);

  state<CounterState>().increment();
  await tester.pump();

  expect(find.text('Count: 1'), findsOneWidget);
});

โš ๏ธ Error Handling

Common error messages and solutions:

// Error: StateBuilder must be used within IStatelessWidget
// Solution: Ensure parent widget extends IStatelessWidget

// Error: State of type X not found
// Solution: Add X to states getter in IStatelessWidget

๐Ÿ”„ Migration

From setState

// Before: StatefulWidget with setState
class CounterWidget extends StatefulWidget {...}

// After: IStatelessWidget with IState
class CounterWidget extends IStatelessWidget {
  @override
  List<IState> get states => [CounterState()];
  ...
}

๐Ÿ“š API Reference

Main Classes

  • IStatelessWidget: Base widget for state management
  • IState<T>: Base class for application states
  • StateBuilder<T>: Widget that rebuilds on state changes
  • state<T>(): Global state accessor function

Key Methods

  • IState.set(T newValue): Update state and notify listeners
  • IState.reset(): Reset to initial value
  • IStatelessWidget.states: Declare required states
  • StateBuilder.builder: Builder function for UI

๐Ÿ“„ License

MIT License - see LICENSE file for details.


iState - Simple, Efficient, Flutter State Management

Libraries

istate