Flutter: Isolating State with Mixins

Carlos Costa

A brief introduction about mixins in dart.

Mixins are a way to add functionality to a class without subclassing it.

Then, we can use that feature to isolate the state of our widgets.

To exemplify this, we will create a simple counter with increment and decrement functionality. Our component will be the following structure.

  • counter.dart - main file of the counter.
  • counter.controller.dart - the controller that will be responsible for the state of the counter.

counter.controller.dart


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

mixin CounterState<T extends Counter> on State<T> {
  int value = 0;

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

  void decrement() {
    setState(() {
      value--;
    });
  }
}

In this file, we have a mixin that will be used to isolate the state of our counter. The mixin will have a value attribute that will be used to store the current value of the counter. We also have two methods increment and decrement that will increment and decrement the value of the value attribute.

The <T extends Counter> on State<T> part of the mixin is used to specify that the mixin can be used with any class that extends Counter and is a State class.

To more details about mixins, you can check the official documentation.

counter.dart


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

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State<Counter> createState() => _CounterState();
}

class _CounterState extends State<Counter> with CounterState {
  @override
  Widget build(BuildContext context) {
    return Column(
      mainAxisAlignment: MainAxisAlignment.center,
      children: [
        ElevatedButton(
          onPressed: increment,
          child: SizedBox(
            width: 120,
            child: Center(child: Text('Increment: $value')),
          ),
        ),
        const SizedBox(
          height: 20,
        ),
        ElevatedButton(
          onPressed: decrement,
          child: SizedBox(
            width: 120,
            child: Center(child: Text('Decrement: $value')),
          ),
        )
      ],
    );
  }
}

In out Counter widget, we can user the CounterState mixin to get access to the value attribute and the increment and decrement methods. Now, we can use our state isolated from the rest of the widget tree.

References