flutter
/

GetX Rx Types: RxInt, RxString, RxList, RxMap & More

Last Sync: Today

On this page

13
0%
5 min read
Remaining
5 minleft

Click any section to jump — progress syncs automatically

flutter

GetX Rx Types: RxInt, RxString, RxList, RxMap & More

What are Rx Types in GetX?

Rx types are the building blocks of reactive state management in GetX. They are observable variables that notify the UI whenever their value changes. GetX provides specialized Rx classes for primitive types, collections, and any custom type through the generic Rx<T>.

  1. Primitive Rx Types

GetX offers dedicated Rx types for common primitive types, each with optimized performance and helpful methods.

DARTRead-only
1
class MyController extends GetxController {
  RxInt count = 0.obs;
  RxDouble price = 19.99.obs;
  RxString name = 'John'.obs;
  RxBool isLogged = false.obs;

  void updateValues() {
    count.value = 10;
    price.value = 24.99;
    name.value = 'Jane';
    isLogged.value = true;
  }
}

  1. Collection Rx Types

GetX provides reactive collections that automatically notify UI when items are added, removed, or modified.

DARTRead-only
1
class MyController extends GetxController {
  RxList<String> items = <String>[].obs;
  RxMap<String, dynamic> userData = <String, dynamic>{}.obs;
  RxSet<int> uniqueIds = <int>{}.obs;

  void manipulateCollections() {
    items.add('New Item');
    items.removeAt(0);
    items.assign(['a', 'b', 'c']); // replace entire list

    userData['name'] = 'Alice';
    userData.remove('age');

    uniqueIds.add(123);
  }
}

  1. Generic Rx Type (Rx<T>)

For custom classes, use the generic Rx<T> type. This allows you to make any object reactive.

DARTRead-only
1
class User {
  String name;
  int age;
  User(this.name, this.age);
}

class MyController extends GetxController {
  Rx<User> user = User('Alice', 30).obs;

  void updateUser() {
    // Update the whole object
    user.value = User('Bob', 25);
    // Or modify properties and refresh
    user.update((user) {
      user?.name = 'Charlie';
    });
  }
}

  1. Accessing and Modifying Values

Each Rx type has a .value getter/setter to access or change the underlying value. For collections, you can also use collection methods directly.

DARTRead-only
1
// Primitive types
final count = 0.obs;
count.value++;  // increment
count.value = 10; // set

// Collections
final items = <String>[].obs;
items.add('apple');  // triggers UI update
items.addAll(['banana', 'orange']);
items.remove('apple');
items[0] = 'grape';  // also triggers update

// Custom types
final user = User('Alice', 30).obs;
user.value.name = 'Bob'; // modifies property but DOES NOT trigger update
user.refresh(); // manually trigger UI update
user.update((u) => u?.name = 'Bob'); // update triggers automatically

  1. Useful Rx Methods

Rx types come with built-in methods to simplify common operations.

  • value – Get or set the current value.
  • refresh() – Manually notify listeners (useful after modifying nested properties).
  • assign(T value) – Replace the entire value (works for all Rx types).
  • assignAll(Iterable<T> iterable) – Replace collection contents with another iterable (for RxList/RxSet).
  • update(void Function(T) fn) – Modify the value inside a callback and automatically notify listeners.
  • bindStream(Stream<T> stream) – Bind an Rx variable to a stream, updating automatically when stream emits.
  • call() – Shortcut for .value (e.g., count() instead of count.value).

  1. Working with Streams

Rx types can be easily connected to streams, making them perfect for real-time data.

DARTRead-only
1
final counter = 0.obs;
final stream = Stream.periodic(Duration(seconds: 1), (i) => i);
counter.bindStream(stream);

// Now counter will automatically update every second

  1. Rx Types with Workers

Workers can listen to Rx variables to react to changes, log, or trigger side effects.

DARTRead-only
1
class MyController extends GetxController {
  var count = 0.obs;

  @override
  void onInit() {
    super.onInit();
    ever(count, (_) => print('Count changed to $count'));
    debounce(count, (_) => print('User stopped incrementing'), time: Duration(seconds: 1));
  }
}

  1. Converting Rx to Non-Rx

Sometimes you need to access the raw value without reactivity. Use .value to get the underlying value.

DARTRead-only
1
final name = 'John'.obs;
String rawName = name.value;

final items = <String>[].obs;
List<String> rawList = items.toList(); // or items.value

  1. Performance Tips

  • Use primitive Rx types for simple values – they're lightweight.
  • Avoid large objects in Rx – break them into smaller reactive pieces if possible.
  • Use update for nested modifications – it's cleaner and ensures notifications.
  • Batch modifications – when updating a collection with many changes, consider using assign or assignAll instead of multiple add/remove calls.
  • Use refresh() sparingly – prefer update or direct value assignment to maintain automatic notifications.

  1. Common Mistakes

  • ❌ Modifying nested properties without refreshing – UI doesn't update. ✅ Use update method or call refresh() after modification.
  • ❌ Using .obs inside build method – Creates new reactive variables on each rebuild. ✅ Declare Rx variables in controllers only.
  • ❌ Assigning a new list without triggering update – items = newList won't work because items is a getter; use items.value = newList or items.assignAll(newList).
  • ❌ Not using .value when needed – print(count) might print the RxInt wrapper, not the number. Use print(count.value).
  • ❌ Comparing Rx values with == – if (count == 0) might not work as expected. Compare using count.value == 0.

FAQ

  • Q: What's the difference between RxInt and int.obs?
    A: int.obs is syntactic sugar that returns an RxInt. They are functionally identical.
  • Q: Can I use RxList with custom objects?
    A: Yes, RxList<User> works perfectly. Ensure your objects are immutable or you call refresh() after modifying them.
  • Q: How do I make a primitive reactive without .obs?
    A: You can use RxInt(0), RxString(''), etc., but .obs is the recommended concise syntax.
  • Q: Why doesn't my UI update when I change a property of a custom object?
    A: Because the Rx variable is observing the object reference, not its properties. Use update or reassign the whole object.
  • Q: What is the call() method?
    A: It's a shorthand for .value. For example, count() returns the current value. This is useful in Obx where you can write Text('${controller.count()}').
  • Q: Can I use Rx with enums?
    A: Yes, Rx<MyEnum>(MyEnum.value1) works perfectly.
  • Q: How do I dispose of Rx variables?
    A: They are automatically disposed when the controller is disposed. You don't need to manually clean them up.
  • Q: Can I use Rx types outside of GetX controllers?
    A: Yes, you can, but then you lose automatic lifecycle management. It's better to keep them inside controllers.

Conclusion

Rx types are the heart of GetX's reactive system. By mastering RxInt, RxString, RxList, RxMap, and the generic Rx<T>, you can build highly responsive Flutter applications. Combine them with workers and best practices for a clean, scalable architecture.

Try it yourself

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

void main() => runApp(MyApp());

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return GetMaterialApp(
      home: RxTypesDemo(),
    );
  }
}

class User {
  String name;
  int age;
  User(this.name, this.age);
}

class RxDemoController extends GetxController {
  // Primitive Rx types
  var count = 0.obs;
  var name = 'GetX'.obs;

  // Collection Rx types
  var items = <String>[].obs;

  // Custom type
  var user = User('Alice', 30).obs;

  void increment() => count++;
  void changeName() => name.value = 'Flutter';
  void addItem() => items.add('Item ${items.length + 1}');
  void updateUserAge() {
    user.update((u) => u?.age++);
  }
}

class RxTypesDemo extends StatelessWidget {
  final controller = Get.put(RxDemoController());

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: Text('Rx Types Demo')),
      body: Padding(
        padding: const EdgeInsets.all(16.0),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('RxInt', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            Obx(() => Text('Count: ${controller.count}', style: TextStyle(fontSize: 24))),
            ElevatedButton(onPressed: controller.increment, child: Text('Increment')),
            SizedBox(height: 16),
            Text('RxString', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            Obx(() => Text('Name: ${controller.name}', style: TextStyle(fontSize: 24))),
            ElevatedButton(onPressed: controller.changeName, child: Text('Change Name')),
            SizedBox(height: 16),
            Text('RxList', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            Obx(() => Column(
              children: [
                ...controller.items.map((item) => Text('- $item')),
                if (controller.items.isEmpty) Text('No items yet'),
              ],
            )),
            ElevatedButton(onPressed: controller.addItem, child: Text('Add Item')),
            SizedBox(height: 16),
            Text('Rx<User>', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            Obx(() => Text('User: ${controller.user.value.name}, Age: ${controller.user.value.age}')),
            ElevatedButton(onPressed: controller.updateUserAge, child: Text('Increment Age')),
          ],
        ),
      ),
    );
  }
}

Test Your Knowledge

Q1
of 3

How do you make an integer reactive in GetX?

A
int.obs
B
RxInt(0)
C
Both of the above
D
None of the above
Q2
of 3

What method should you use to modify a nested property of a custom object and automatically notify the UI?

A
refresh()
B
update()
C
assign()
D
value()
Q3
of 3

Which of the following correctly replaces the contents of an RxList?

A
items = ['a', 'b'];
B
items.value = ['a', 'b'];
C
items.assignAll(['a', 'b']);
D
Both B and C

Previous

getx simple state

Next

getx workers

Related Content

Need help?

Explore our comprehensive docs or start a chat with our tech experts.