Open In App

State management using Redux in Flutter

Last Updated : 23 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

State management is a crucial aspect of building dynamic and responsive applications. While building applications, we sometimes need to maintain a state between multiple screens. Here comes the part of State Management. There are different state management techniques in Flutter like GetX, Provider, BloC and Redux.

Redux is a state management library initially created for JavaScript applications. It was developed by Dan Abramov and Andrew Clark in 2015, inspired by the Flux architecture by Facebook. Redux is a predictable state management library commonly used in Flutter. It helps programmers implement a centralized store that can be accessed throughout the entire application. It has some principles which are given below.

Principle of Redux

  1. Single Source of Truth: The state of the app is stored in a single object called the store. This centralization of state helps developers to easily debug apps.
  2. State is Read-Only: In Redux, we can change the state only by emitting an action, and the object describes what happened. This will always ensure that views or components do not directly modify the state.
  3. Changes Made with Pure Functions: Pure functions are written to specify how the state is going to transform. The pure function is called a reducer. The reducer takes the previous state and an action and returns the next state.

Working of Redux

Redux works in a unidirectional way. It distributes data across multiple widgets in a repetitive manner.

before-state
Before State Management


In the above example, the generated data in Widget-A is needed in Sub-Widget-3. Traditionally, data is passed through the Widget-D to Sub-Widget-2 and then finally to Sub-Widget-3. In this case, the data may be saved in the upper widget tree, and whenever required, it gets sent down the widget tree.

With the help of Redux we can overcome this problem. Instead of passing the data down the widget tree, we can maintain data in a centralized-store. This store maintains the state of the application. The data in this centralized store can be accessed by any widget without needing to pass thought chain of other widgets in widget tree.

after-state
After State Management


Implementing Redux In Flutter

In this article we are practically implementing the redux. For this we are making a basic app which will display a random number or alphabet when a button is pressed. while building the app we are not focusing on the UI but we are emphasizing on the implementing functionality with Redux. Let's see a demo video of what we are going to develop.

Demo Video:


Step 1: Create a new Flutter Application

Create a new Flutter application using the command Prompt. To create a new app, write the following command and run it.

flutter create app_name

To know more about it refer this article: Creating a Simple Application in Flutter

Step 2: Adding the Dependency

To add the dependency to the pubspec.yaml file, add redux and flutter_redux as a dependency in the dependencies part of the pubspec.yaml file, as shown below:

Dart
dependencies:
     flutter:
       sdk: flutter
     redux: ^5.0.0
     flutter_redux: ^0.10.0

Now, run the command below in the terminal.

flutter pub get

Or

Run the below command in the terminal.

flutter pub add redux flutter_redux


Step 3: Creating The Store

The state of an application is the state representation of the app at a point in time. The store is the object that brings together the state, actions, and reducers. In this example, we create a store that generates random values.

final store = Store(generateRandomValues, initialState: 'Initial Value');

Store is a class that is used to create a new Redux store. As we discussed earlier, Store holds the state of our app. In this snippet, generateRandomValues is the reducer function, which is a pure function that takes the previous state and an action, and returns the next state. initialState indicated the initial state of the store to string 'Initial Value'.


Step 4: Defining Actions

Actions are fundamental form of information. They are stored as plain dart objects and describes an event or change that need to be made in application state. Actions are dispatched in response to user interactions with the application, such as button clicks or form submission.

enum RandomTypes { Numbers, Alphabets }

In the above code snippet. We have defined two types of actions here, Numbers and Alphabets. These actions can be dispatched to the store.

When an actions is dispatched, The redux store invokes the reducer function with current state and dispatches the action. The reducer function, based on the action type, performs the necessary state transition and returns the new state.


Step 5: Creating Reducers

Reducers are pure functions. They specify how the application's state changes in response to actions sent to the store.

Dart
generateRandomValues(dynamic value, dynamic action) {
    if (action == RandomTypes.Numbers) {
        return value = Random().nextInt(100);
    }
    if (action == RandomTypes.Alphabets) {
        return value = String.fromCharCode(Random().nextInt(26) + 65);
    }
}

In this example, we have declared a reducer that generates random values based on the action type. This function generates a random number or a random uppercase alphabet letter, respectively, and returns a new state.


Step 6: Connecting Redux to the Flutter App

Now the crucial step comes in, To connect redux to the flutter app we can use StoreProvider widget. This widget takes a Store and a child, and it will provide the Store to all descendant of the child.

Dart
class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.store});

  final Store<dynamic> store;

  @override
  Widget build(BuildContext context) {
    return StoreProvider<dynamic>(
      store: store,
      child: MaterialApp(
        
      ),
    );
  }
}


Complete Source Code

main.dart:

main.dart
import 'dart:math';
import 'package:flutter/material.dart';
import 'package:flutter_redux/flutter_redux.dart';
import 'package:redux/redux.dart';

void main() async {
  final store = Store(generateRandomValues, initialState: 'Initial Value');
  runApp(MyApp(store: store));
}

enum RandomTypes { Numbers, Alphabets }

generateRandomValues(dynamic value, dynamic action) {
  if (action == RandomTypes.Numbers) {
    return value = Random().nextInt(100);
  }
  if (action == RandomTypes.Alphabets) {
    return value = String.fromCharCode(Random().nextInt(26) + 65);
  }
}

class MyApp extends StatelessWidget {
  const MyApp({super.key, required this.store});

  final Store<dynamic> store;

  @override
  Widget build(BuildContext context) {
    return StoreProvider<dynamic>(
      store: store,
      child: MaterialApp(
        debugShowCheckedModeBanner: false,
        home: Scaffold(
          appBar: AppBar(
            title: const Text('Redux App'),
            centerTitle: true,
            backgroundColor: Colors.black,
            foregroundColor: Colors.white,
          ),
          body: Container(
            child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
                StoreConnector<dynamic, String>(
                  converter: (store) => store.state.toString(),
                  builder: (context, value) {
                    return Text(
                      value,
                      style: const TextStyle(
                        fontSize: 30,
                        fontWeight: FontWeight.bold,
                      ),
                    );
                  },
                ),
                Row(
                  mainAxisAlignment: MainAxisAlignment.spaceEvenly,
                  children: <Widget>[
                    ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.black,
                        foregroundColor: Colors.white,
                      ),
                      onPressed: () {
                        store.dispatch(RandomTypes.Numbers);
                      },
                      child: const Text('Random Number'),
                    ),
                    ElevatedButton(
                      style: ElevatedButton.styleFrom(
                        backgroundColor: Colors.black,
                        foregroundColor: Colors.white,
                      ),
                      onPressed: () {
                        store.dispatch(RandomTypes.Alphabets);
                      },
                      child: const Text('Random Alphabet'),
                    ),
                  ],
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

Output:

Conclusion

Redux provides a robust solution for managing state in Flutter applications. In this article we have seen some basic principles of redux along with how to implement them. We have built a simple flutter app using redux state management, which will generate random number and character.


Next Article
Article Tags :

Similar Reads