Redux

A portrait painting style image of a pirate holding an iPhone.

by The Captain

on
July 21, 2023

Title: Flutter Redux - Managing State Efficiently

Redux is a powerful state management framework for Flutter that allows developers to manage application state efficiently. It implements the Flux architecture, which provides a unidirectional data flow and makes it easier to understand how data is modified and propagated throughout the app.

Installation

To get started with Redux in your Flutter project, you need to include the flutter_redux package in your pubspec.yaml file:


dependencies:
 flutter_redux: ^0.10.0

After adding the package, run the following command to fetch the dependencies:


$ flutter packages get


Usage

Let's dive into a simple example to see how Redux works in practice. Suppose we have a counter app, and we want to manage the current count value using Redux.

First, we need to define the actions that can be performed on the counter state. Create a new file called actions.dart:


class IncrementAction {
 final int amount;
 IncrementAction(this.amount);
}
class DecrementAction {
 final int amount;
 DecrementAction(this.amount);
}

In this example, we define two actions: IncrementAction and DecrementAction. These actions represent the actions that can be performed on the counter state. Each action class takes an amount parameter to specify the amount by which the counter should be incremented or decremented.

Next, let's define the reducer which handles these actions and updates the state accordingly. Create a new file called reducer.dart:


import 'actions.dart';

int counterReducer(int state, dynamic action) {
 if (action is IncrementAction) {
  return state + action.amount;
 } else if (action is DecrementAction) {
  return state - action.amount;
 }
 return state;
}

In this reducer, we handle the IncrementAction and DecrementAction by updating the state (counter value) based on the provided amount. If the action is neither of these types, we simply return the current state.

Now let's create the Redux store and connect it to our Flutter app. In the main.dart file, add the following code:


import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';
import 'actions.dart';
import 'reducer.dart';

void main() {
 final store = Store(counterReducer, initialState: 0);
 runApp(MyApp(store: store));
}

class MyApp extends StatelessWidget {
 final Store store;

 MyApp({required this.store});

 @override
 Widget build(BuildContext context) {
  return StoreProvider(
   store: store,
   child: MaterialApp(
    title: 'Redux Demo',
    home: CounterScreen(),
   ),
  );
 }
}

In this code snippet, we create a Redux store using the counterReducer and an initial state of 0. The store is then passed to the MyApp widget using a StoreProvider. This provider allows widgets in the widget tree to access the store.

Finally, let's create a CounterScreen widget to display the counter value and provide buttons to increment and decrement it:


class CounterScreen extends StatelessWidget {
 @override
 Widget build(BuildContext context) {
  return Scaffold(
   appBar: AppBar(title: Text('Redux Demo')),
   body: Center(
    child: Column(
     mainAxisAlignment: MainAxisAlignment.center,
     children: [Text('Counter:'),
        StoreConnector(
         converter: (store) => store.state.toString(),
         builder: (context, counter) {
          return Text(counter);
         },
        ),
        ElevatedButton(onPressed: () => StoreProvider.of(context).dispatch(IncrementAction(1)), child: Text('Increment')),
        ElevatedButton(onPressed: () => StoreProvider.of(context).dispatch(DecrementAction(1)), child: Text('Decrement'))]
     ),
   ),
  );
 }
}

In this code, we use the StoreConnector widget to obtain the counter value from the Redux store and display it. We also dispatch the IncrementAction and DecrementAction when the corresponding buttons are pressed.

With Redux, managing state in Flutter becomes easier and more predictable. The unidirectional data flow ensures that all state modifications follow a clear pattern, making it easier to debug and reason about your app's behavior.