Are you using setState() correctly?

Are you using setState() correctly?

Flutter Provider Tutorial

Are you using setState() correctly? Or have you noticed how many times the build() method is called? If not then keep reading this article where I will talk about Provider implementation and a common mistake I was doing with setState().

Before we begin with the provider concept, I wanna tell you...

The mistake that I made as a beginner!!

So what I used to do is, apply setState() everwhere possible. And that is what people are doing because they have been told that setState() is the way to update the UI. So I'm going to show you how to do this properly with the help of a provider.

Creating the UI

Suppose we have a use case where we need to use a back-off timer on the Resend OTP button to send the OTP request so the user cannot exploit the API.

What the back-off timer will do is when the user clicks the resend OTP button it starts a timer for 60sec and the button will be disabled till the timer value reaches 0 again.

First, we create the basic UI for our timer

Here, we've just created a basic UI which consists of a Logo, a SizedBox, and an ElevatedButton wrapped inside a Column widget.

Create method for the starting timer

Just add the startTimer() method above the build method.

Here we are decrementing the value of timeLeft variable by 1 every second and calling setState() to update the UI to show the updated time left for resending the OTP. And when the timer is finished Line-6 we again update the value of timeLeft variable to 30 seconds to the button is enabled again.

Let's run the app and click the Send OTP button. The timer starts and the button is disabled till the timer is finished.

This is because we are using setState() method every 1 second to update the timeLeft variable value on Line 3-5 and cancelling the timer when the timeLeft is < 0 Line 6-11.

So What's wrong with this ??

You might ask Hey, this is working fine then what's wrong with doing thisway? It's quite easy to update just update the value using setState().

The main problem with this approach is that it's rendering the entire page each second just for proof, Now if you have a look at the debug console you can see the build method is called every second the timer value is updated. The Image is redrawn, the sizedBox is redrawn, and the ElevatedButton too. We don't want that because for this kind of a simple page it is fine, but what id we have a page like

where the timer is nested deep down the widget tree and it will cost you in terms of performance if you apply the above method.

Explanation

  1. ChangeNotifierProvider -> Entry

  2. Provider.of<>() -> Interaction

  3. Consumer -> User

  4. ChangeNotifier -> Data Holder

    ChangeNotifierProvider which creates the instance of your data and hold it. From anywhere inside your page if you want to update the value you just get the instance of that provider and you can manipulate the value as soon as the value is changed it will notify all the consumer once the consumer gets data you can update your widget accordingly without affecting any of this hierarchy.

Implementation

The first thing we need to implement is the provider package itself, so open the pubspec.yaml file and just add the provider package under dependencies.

dependencies:
  cupertino_icons: ^1.0.2
  flutter:
    sdk: flutter
  provider: ^6.0.5

So after adding the package the first task is to create a model which will hold the data so I'm going to create a new file name timer_info.dart and add the following code

We declare a variable which holds the remaining time, after that we'll create a getter getTimeLeft() and setter updateTimeLeft(). The resetTimer() method is used to reset the timer value once the timers is completed.

IMP: We extends our class to ChangeNotifier to use notifyListener**()** method at Line 10. So whenever there is an update in the value we will call notifyListners() method to trigger the consumer so that now it can update the UI.

So the next step is to create the instance of this timer or info inside our page i.e. the startTimer() method from where we are going to update the value so we want the information at this page level.

We are going to create it in the main.dart file in the homepage and wrap the Homepage() with widget called ChangeNotifierProvider and pass the instance of TimerInfo() in the create parameter.

what this will do is, it will provide the instance of TimerInfo() anytime in the HomePage wherever we need it.

Modify the HomePage class

Let's get the instance in HomePage class, we will create a variable which will hold this timerInfo method and variable in the startTimer() method Line 3-7. As we are getting the instance from outside the visual tree we need to pass false to the listen parameter at Line 3.

Now we need to modify the ElevatedButton to consume the data from the provider. To do this we will wrap the ElevatedButton with Consumer and use the data variable to with a dot operator to access the variable and methods.

That's it !!

You have successfully implemented Provider and optimised the Performance of the application.

Now run the app and click the Send Otp button and have a look in the debug console that how many times this widget is getting rendred. You'll notice that it is called only once and it's not rendering the image FLutter Logo and other widgets again and again each second.

Does this makes any sense

As this is a simple example you may think this is a very minor thing but if you have a complex example as I said earlier this makes difference and your application will perform much better.

Hopping you understand the whole concept and thank you so much for reading the article.

Share This Tutorial

👉 Please share my posts with the community at daily.dev / social media by adding the article's URL to the feed.

By adding my article, I can share my insights and knowledge with other tech enthusiasts and contribute to the passionate community.

Cheers✨