As we navigate the vast landscape of app development using Flutter, there are specific code-shareable technologies that could bring efficiency to our work. One technology that assists Flutter developers in managing state is the useReducer hook.
This blog post sheds light on this powerful tool - the useReducer hook - and how it manages the local state in even the most complex applications. We will study its working mechanism, implement it in a Flutter project, compare it with traditional methods, and illustrate how it can save time and increase code sharing.
By the end of reading this blog, you should have a comprehensive understanding of the useReducer hook. You will learn precisely how to implement it and where it can be put to best use while keeping your Flutter code tidy and efficient.
Flutter gave us a brilliant way to manage states through hooks even before introducing the useReducer hook. With a basic grounding in how hooks function in Flutter, let's explore the technicality of hooks and why they are pivotal in creating Flutter applications.
Hooks are a revolutionary feature in Flutter that allows developers to manage states and side effects in function components. There is no doubt that hooks are one of the most notable additions in the Flutter world that have eased the life cycle of widgets by removing some boilerplate code.
Within your function components, consider using hooks if you're looking to manage local states, perform HTTP requests, handle animation controllers, and much more without converting your functions into classes.
1import 'package:flutter_hooks/flutter_hooks.dart'; 2 3// Here's an example of a HookWidget managing local states 4class MyHomePage extends HookWidget { 5 const MyHomePage({Key key}) : super(key: key); 6 7 @override 8 Widget build(BuildContext context) { 9 // manage local state using useState hook 10 final count = useState(0); 11 12 return Scaffold( 13 body: Center(child: Text("Count: ${count.value}")), 14 floatingActionButton: FloatingActionButton( 15 onPressed: () => count.value++, // handle state changes 16 child: const Icon(Icons.add), 17 ), 18 ); 19 } 20}
In the above code, we created a simple counter app using useState hook, a commonly used hook, before introducing useReducer hook. Hooks have simplified managing widget states, but they can get messy when your application starts to grow.
As we proceed further, we uncover the wonders of the useReducer hook - a more organized and scalable solution specifically designed for complex states with multiple sub-values.
In the world of Flutter, hooks have been helping developers manage various aspects of their Flutter projects. From handling local state and WebSocket connections to managing active HTTP connections, Flutter hooks present incredible utility in code sharing and reducing the boilerplate code.
One class that truly stands out among these hooks is the useReducer hook. Let's dive into what makes this hook special.
The useReducer hook helps manage complex states in a much more organized and efficient manner. When working with states that have multiple sub-values, the useState hook can lead to bulky widgets and tangled logic. Here, the useReducer hook jumps in.
Think of an application's state as an object with multiple keys and values. The user interaction triggers actions with a new value that produces a new state, replacing the current state. The useReducer hook helps us manage these multiform states effectively.
The useReducer hook adds much-needed structure and reduces complexity compared to using setState or useState hooks, thereby increasing code sharing throughout your Flutter project.
1import 'package:flutter_hooks/flutter_hooks.dart'; 2 3class MyHomePage extends HookWidget { 4 const MyHomePage({Key key}) : super(key: key); 5 6 @override 7 Widget build(BuildContext context) { 8 // use of useReducer hook 9 final count = useReducer<int, int>((value, action) => value + action, initialAction: 0); 10 11 return Scaffold( 12 body: Center(child: Text("Count: ${count.value}")), 13 floatingActionButton: FloatingActionButton( 14 onPressed: () => count.action(1), 15 child: const Icon(Icons.add), 16 ), 17 ); 18 } 19}
In the above code, we've adapted the earlier count example to use the useReducer hook instead. As you can see, it gives us a clear structure and improves our capacity to handle complex states with ease.
With this basic grasp of the useReducer hook's role in Flutter, we can delve deeper into its working mechanism.
Custom hooks, like the useReducer hook in Flutter, are superior tools for managing local state within function components. The hook's beauty and utility lie in its simple yet powerful mechanism that allows for the efficient management of complex states.
For any Flutter developer, understanding the workings of the useReducer hook can be a huge asset. This hook uses a reducer function and an initial state as its argument, returning the current state and a method to dispatch actions.
The reducer function accepts two parameters: the current state and an action. It determines how to transition from the current state to the next based on the action received.
1import 'package:flutter_hooks/flutter_hooks.dart'; 2 3class CounterApp extends HookWidget { 4 @override 5 Widget build(BuildContext context) { 6 final counter = useReducer<int, int>((value, action) { 7 // Check type of action and modify state appropriately 8 if (action > 0) return value + action; 9 if (action < 0) return value - 1; 10 return value; 11 }, initialAction: 0); 12 13 return Scaffold( 14 appBar: AppBar( 15 title: Text("Counter App") 16 ), 17 body: Center( 18 child: Text("Counter Value: ${counter.value}") 19 ), 20 floatingActionButton: FloatingActionButton( 21 onPressed: () => counter.action(1), // increment counter 22 child: const Icon(Icons.add), 23 ), 24 ); 25 } 26}
In the code above, we have a CounterApp which uses the useReducer hook to manage the counter state. We pass in the reducer function responding to action values and an initial state of 0. The hook returns an instance of action, which we can call with a new value whenever needed.
As we've seen in the previous part, the useReducer Flutter hook can significantly simplify state management in your apps, especially when dealing with complex states. Before fully deploying its power in our widgets, we should understand its working mechanism.
The useReducer hook operates through three primary components – the reducer function, the initial state, and the dispatch method.
The function instance you pass to useReducer becomes your reducer function. The reducer function is responsible for taking the current state and action as arguments and returning a new state based on these inputs.
The initial state is the value that gets used during the first render of the component. It's simply the state where the reducer function starts operating.
The dispatch method is a function callback that initiates the sequence of updating the state. The dispatch method accepts an action, which passes to the reducer function as the second argument.
Let's illustrate this through a simple example:
1import 'package:flutter_hooks/flutter_hooks.dart'; 2 3class MyHomePage extends HookWidget { 4 5 MyHomePage({Key key}) : super(key: key); 6 7 @override 8 Widget build(BuildContext context) { 9 10 final AnimationController controller = useAnimationController(duration: Duration(seconds: 1)); // our Animation controller 11 12 useEffect(() { 13 controller.forward(); 14 return () => controller.dispose(); // Clean up using useEffect hook 15 }, []); 16 17 return Scaffold( 18 body: Center( 19 child: RotationTransition( 20 turns: controller, 21 child: FlutterLogo(size: 200.0), 22 ), 23 ), 24 ); 25 } 26}
In the code block above, we look at how you can use the useEffect hook and AnimationController to rotate a Flutter logo. Although there's no useReducer hook here, the example is to illustrate how to work with hooks.
Now that we've gone through the theoretical understanding of the useReducer hook let's see how we can implement it in an actual Flutter application.
Before you can create a new Flutter project, you should make sure to have Flutter and Dart correctly installed on your machine. You'll also need an editor like VSCode or Android Studio.
Start a new Flutter project by running the command flutter create use_reducer_example in your terminal or command prompt.
In our main.dart file, we'll begin by importing the 'package:flutter_hooks/flutter_hooks.dart' package. We'll create a StatefulWidget for the counter, starting with 0.
1import 'package:flutter/material.dart'; 2import 'package:flutter_hooks/flutter_hooks.dart'; 3 4void main() { 5 runApp(MaterialApp( 6 home: CounterApp(), 7 )); 8} 9 10class CounterApp extends HookWidget { 11 const CounterApp({Key key}) : super(key: key); 12 13 @override 14 Widget build(BuildContext context) { 15 16 // useReducer hook in action 17 final counter = useReducer<int, int>((value, action) => value + action, initialAction: 0); 18 19 return Scaffold( 20 appBar: AppBar( 21 title: const Text('Counter using useReducer Hook') 22 ), 23 body: Center( 24 child: Text("Count: ${counter.value}", style: TextStyle(fontSize: 24),), 25 ), 26 floatingActionButton: FloatingActionButton( 27 child: const Icon(Icons.add), 28 onPressed: () => counter.action(1), 29 ), 30 ); 31 } 32}
Like any other hooks in Flutter, the useReducer hook has advantages and limitations that can affect how we approach state management in our applications.
Let's kick off with the merits of using the useReducer hook:
1final counter = useReducer<int, int>((value, action) { 2 if(action == 0) { 3 // Do something 4 } else if (action == 1) { 5 // Do something else 6 } 7 return value; 8}, initialAction: 0);
In the above example, the reducer function handles various actions differently - a pattern common in larger applications.
The useReducer hook is not without its downsides:
Despite the hurdles, grappling with the use of the useReducer hook is worthwhile for the power and flexibility it offers in managing complex state logic.
The introduction of hooks to Flutter brought about a paradigm shift in how developers manage state. While traditional state management techniques are still relevant and widely used, let's see where the useReducer hook stacks up against them.
In many scenarios, developers might consider using the useState or useReducer hook. However, there's a key distinction between these two hooks used in managing local states.
The useState hook is simpler and easier for managing simpler states, like toggling a Boolean or increasing a counter in a single widget.
On the other hand, the useReducer hook comes into its own when dealing with complex states with multiple sub-values. By managing them under one state object using the useReducer hook, Flutter developers can simplify the code sharing and the overall application.
Provider is a popular state management technique that allows us to expose a value to the widget tree and redraw widgets that depend on this value. However, the Provider alone does not handle business logic.
The useReducer hook, on the other hand, excels at complex state logic and guides us in handling asynchronous functions in our app.
Choosing between the Provider and the useReducer hook depends on your app's requirements.
The useReducer hook in Flutter plays a significant role in managing complex states within an application. As we've seen throughout this blog, it's a powerful tool that leverages the simplicity of pure functions and the scalability of reducers.
The useReducer hook brings an organized structure to the function components and enhances the clarity of state changes. It's an excellent alternative to other hooks and traditional state management techniques when dealing with more complex state changes in Flutter applications.
To sum up, the useReducer hook, while it has its learning curve, could be a hugely beneficial tool in developing intuitive and efficient Flutter apps if leveraged correctly.
For those interested in exploring deeper into the useReducer Hook in Flutter and the different possibilities it offers, the following resources will be instrumental:
Happy coding!
Tired of manually designing screens, coding on weekends, and technical debt? Let DhiWise handle it for you!
You can build an e-commerce store, healthcare app, portfolio, blogging website, social media or admin panel right away. Use our library of 40+ pre-built free templates to create your first application using DhiWise.