Flutter GetX

All-in-one solution for state, routing, and dependency injection

⚡ What is GetX?

GetX is a lightweight, powerful Flutter solution combining state management, routing, and dependency injection. It offers minimal boilerplate, high performance, and reactive programming with simple syntax, making development faster and more enjoyable for all skill levels.


// Simple reactive variable
final count = 0.obs;
                                    

Key Concepts

🎯

Simple State

Minimal boilerplate code

final name = 'John'.obs;
name.value = 'Jane';
🚀

Fast Routing

Navigate without context

Get.to(NextPage());
Get.back();
💉

Dependency Injection

Easy dependency management

Get.put(Controller());
Get.find<Controller>()

High Performance

Optimized rebuilds

Obx(() => 
  Text('${count}'))

🔹 Installation

Add GetX to your pubspec.yaml:

dependencies:
  flutter:
    sdk: flutter
  get: ^4.6.5

Then run:

flutter pub get

🔹 Basic Counter Example

Create a counter using GetX:

import 'package:flutter/material.dart';
import 'package:get/get.dart';

// 1. Create a Controller
class CounterController extends GetxController {
  // Observable variable
  var count = 0.obs;
  
  void increment() {
    count++;
  }
  
  void decrement() {
    count--;
  }
}

// 2. Use GetMaterialApp instead of MaterialApp
void main() {
  runApp(GetMaterialApp(
    home: CounterPage(),
  ));
}

// 3. Use the controller in your widget
class CounterPage extends StatelessWidget {
  // Instantiate controller
  final CounterController controller = Get.put(CounterController());
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('GetX Counter')),
      body: Center(
        // Obx rebuilds only this widget
        child: Obx(() => Text(
          '${controller.count}',
          style: TextStyle(fontSize: 48),
        )),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: controller.increment,
        child: Icon(Icons.add),
      ),
    );
  }
}

Output:

A counter app that increments when the button is pressed using GetX.

🔹 Reactive State Management

Three ways to make variables reactive:

class MyController extends GetxController {
  // Method 1: .obs (Observable)
  var name = 'John'.obs;
  var age = 25.obs;
  var isActive = true.obs;
  
  // Method 2: Rx types
  RxString email = '[email protected]'.obs;
  RxInt score = 0.obs;
  RxList<String> items = <String>[].obs;
  
  // Method 3: GetBuilder (simple state)
  int counter = 0;
  
  void updateName(String newName) {
    name.value = newName; // Update observable
  }
  
  void incrementCounter() {
    counter++;
    update(); // Manually trigger rebuild for GetBuilder
  }
}

// Usage in UI
class MyWidget extends StatelessWidget {
  final controller = Get.put(MyController());
  
  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        // Obx for reactive variables
        Obx(() => Text(controller.name.value)),
        
        // GetBuilder for simple state
        GetBuilder<MyController>(
          builder: (ctrl) => Text('${ctrl.counter}'),
        ),
      ],
    );
  }
}

Output:

Different approaches to reactive state management in GetX.

🔹 Navigation with GetX

Navigate without BuildContext:

// Simple navigation
Get.to(NextPage());

// Named routes
Get.toNamed('/details');

// Go back
Get.back();

// Replace current page
Get.off(HomePage());

// Clear all and go to page
Get.offAll(LoginPage());

// Pass data
Get.to(DetailsPage(), arguments: {'id': 123});

// Receive data
final args = Get.arguments;

// Show snackbar
Get.snackbar(
  'Title',
  'Message',
  snackPosition: SnackPosition.BOTTOM,
);

// Show dialog
Get.defaultDialog(
  title: 'Alert',
  middleText: 'Are you sure?',
  onConfirm: () => Get.back(),
);

// Show bottom sheet
Get.bottomSheet(
  Container(
    height: 200,
    color: Colors.white,
    child: Center(child: Text('Bottom Sheet')),
  ),
);

Output:

Various navigation methods available in GetX without needing context.

🔹 Dependency Injection

Manage dependencies easily:

// Put: Create and keep in memory
Get.put(ApiController());

// Lazy: Create only when needed
Get.lazyPut(() => DatabaseController());

// Put async: For async initialization
Get.putAsync(() async {
  final controller = await ApiController.init();
  return controller;
});

// Find: Get existing instance
final api = Get.find<ApiController>();

// Delete: Remove from memory
Get.delete<ApiController>();

// Example usage
class ApiController extends GetxController {
  Future<void> fetchData() async {
    // API logic
  }
}

class HomePage extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    // Get the controller
    final api = Get.find<ApiController>();
    
    return Scaffold(
      body: Center(
        child: ElevatedButton(
          onPressed: () => api.fetchData(),
          child: Text('Fetch Data'),
        ),
      ),
    );
  }
}

Output:

Dependency injection patterns in GetX for managing controllers and services.

🔹 Todo List Example

A complete example with GetX:

class TodoController extends GetxController {
  var todos = <String>[].obs;
  var textController = TextEditingController();
  
  void addTodo() {
    if (textController.text.isNotEmpty) {
      todos.add(textController.text);
      textController.clear();
      Get.snackbar('Success', 'Todo added!');
    }
  }
  
  void removeTodo(int index) {
    todos.removeAt(index);
  }
  
  @override
  void onClose() {
    textController.dispose();
    super.onClose();
  }
}

class TodoPage extends StatelessWidget {
  final controller = Get.put(TodoController());
  
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('GetX Todo List')),
      body: Column(
        children: [
          Padding(
            padding: EdgeInsets.all(16),
            child: Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: controller.textController,
                    decoration: InputDecoration(
                      hintText: 'Enter todo',
                    ),
                  ),
                ),
                IconButton(
                  icon: Icon(Icons.add),
                  onPressed: controller.addTodo,
                ),
              ],
            ),
          ),
          Expanded(
            child: Obx(() => ListView.builder(
              itemCount: controller.todos.length,
              itemBuilder: (context, index) {
                return ListTile(
                  title: Text(controller.todos[index]),
                  trailing: IconButton(
                    icon: Icon(Icons.delete),
                    onPressed: () => controller.removeTodo(index),
                  ),
                );
              },
            )),
          ),
        ],
      ),
    );
  }
}

Output:

A complete todo list app with add and remove functionality using GetX.

🔹 GetX Utilities

Helpful utilities built into GetX:

// Responsive design
Get.width;  // Screen width
Get.height; // Screen height
Get.context; // BuildContext
Get.theme;  // ThemeData

// Platform checks
GetPlatform.isAndroid;
GetPlatform.isIOS;
GetPlatform.isWeb;

// Internationalization
Get.locale; // Current locale
Get.updateLocale(Locale('es', 'ES'));

// Theme switching
Get.changeTheme(ThemeData.dark());
Get.changeThemeMode(ThemeMode.dark);

// Validation
GetUtils.isEmail('[email protected]');
GetUtils.isPhoneNumber('+1234567890');
GetUtils.isURL('https://example.com');

Output:

Various utility functions provided by GetX for common tasks.

🔹 When to Use GetX

✅ Good For:

  • Rapid development and prototyping
  • Small to medium-sized apps
  • When you want an all-in-one solution
  • Developers who prefer minimal boilerplate
  • Apps needing simple navigation and state

❌ Consider Alternatives For:

  • Very large enterprise applications
  • Teams preferring official Google solutions
  • When you need strict architectural patterns
  • Projects requiring extensive testing frameworks

🔹 GetX Best Practices

  • Use Get.lazyPut(): For better memory management
  • Dispose controllers: Override onClose() to clean up resources
  • Use Obx sparingly: Only wrap widgets that need to rebuild
  • Separate business logic: Keep controllers focused and testable
  • Use GetView: For widgets that use a single controller

🧠 Test Your Knowledge

What widget is used to rebuild UI when observable changes in GetX?