DEV Community

Ali Çimen
Ali Çimen

Posted on

Facing State Management: "Truly" Understanding Provider in Flutter

The Beginning: Why This Project?

You somehow learn to build UIs in Flutter, but when it comes to state management, it's a wall you inevitably hit. To truly understand Provider instead of just memorizing code by copying and pasting, I built a cart management app called "Sneaker Shop." My goal was to focus purely on the data's journey between screens and the logic behind Provider. Because of this, I intentionally kept the UI minimal and used basic widget structures rather than complex designs.

The Fundamentals of Provider: The "Radio Station" Analogy

At its core, Provider is like a radio station you set up in the middle of your app. Instead of passing data through complex paths between your pages (widgets), they just put on their headphones and listen directly to this central station.

The brain of this station is the ChangeNotifier class. You store your data inside this class, and when a change occurs (like a new item being added to the cart), you grab the microphone and make an announcement using the notifyListeners() function. The pages listening to this announcement instantly update themselves with the new data.

How I Set Up Provider in the Project

I built the core cart logic—the heart of the e-commerce app—in two main steps:

  1. Setting Up the Broadcast Tower: First, at the very top of my app in the main.dart file, I defined a MultiProvider (to keep it scalable for the future). This allowed all the pages inside the app to access this state.
  2. Writing the Brain (Provider Class): I created a CartProvider class and defined a private cart list inside it. I wrote functions to add, remove, and completely clear the cart. To notify the UI after each action, I added notifyListeners() to the end of these functions. I also used a sleek .fold() method to calculate the total price of the items in the cart dynamically.

My Learning Strategy: Pair Programming with AI

While building this project, I set a strict rule for myself: use AI not as an assistant, but as a "pair programmer."

Whenever I moved to a new structure, I first let the AI write the skeleton code and analyzed how it worked. Then, I closed the screen and rewrote the exact same code entirely by hand without looking anywhere. It was an amazing method to build muscle memory after understanding the logic.

My Badges of Honor: 69 Errors and the Power of a Single Letter

Of course, writing everything from scratch by hand comes with a funny cost. When I reached the end of the project and tried to compile it, I suddenly faced 69 errors on the screen! I panicked briefly before realizing there were zero logic flaws; it was entirely a "domino effect" caused by:

  • Forgetting to add the import path of a page in main.dart.
  • Typing lengt instead of length, swallowing a single "h".
  • Writing the Colors.red class with a lowercase letter as colors.red.
  • And those innocent missing commas that wreaked havoc on the widget tree...

They were all sweet mistakes born from touching the code with my own hands.

The Biggest Lesson Learned: Read vs. Watch

The most valuable skill this simple project taught me was moving the context.read vs. context.watch distinction out of memorization and into logical understanding.

If I just needed to click a button to add an item to the cart without needing to listen to an instant change on the screen, I used the triggering read method to boost performance:

// We only trigger the action; we don't unnecessarily rebuild the UI.
context.read<CartProvider>().addToCart(product);

Enter fullscreen mode Exit fullscreen mode

However, on the cart page, where I needed to calculate and display the items and the total price instantly, I used watch to listen to the radio live and keep the data synchronized with the UI:

// This page updates instantly every time notifyListeners() runs in the Provider.
final cart = context.watch<CartProvider>();

Enter fullscreen mode Exit fullscreen mode

In the end, by making mistakes and fixing them, I completely grasped the Provider lifecycle. You can find all the source code and the folder architecture of the app on my GitHub repo: []


Top comments (0)