State Management in FlutterFlow: Building Custom Widgets with Shared State

State Management in FlutterFlow: Building Custom Widgets with Shared State

By:
Roberto Requena
Published on:
August 23, 2024

Among the no-code platforms available today, FlutterFlow stands out as one of my favorites. It combines the convenience of no-code and low-code development with the flexibility to add custom code to solve some of the platform's limitations. The FlutterFlow team has been making rapid progress in improving its platform, but as with any tool, there may be times when you encounter a wall when you’re trying to implement a specific feature or requirement. In this tutorial, we'll explore overcoming one such obstacle: sharing state from a custom widget in FlutterFlow.

FlutterFlow held its Component Carnival contest a few weeks ago, and I was thrilled to participate. I created a custom component to share with the community: an image upload component that allows users to edit their photos before uploading them to Firebase Firestore. FlutterFlow doesn't support these editing capabilities out of the box, so I had to develop a custom widget to make it happen.

Once I developed my custom component, I realized I needed to share the edited image data with the rest of my app. However, I soon hit a roadblock, my custom widget was like a black box to FlutterFlow, and the platform didn't have a straightforward way to access the widget's state.

Custom Components

To be clear, when you create a custom component on FlutterFlow, the platform offers some default capabilities to access the information on the custom component and its state. For example, we have a custom component that contains a text field. And this can be accessed using a built-in feature that provides access to the text value of the field.
In the case of our button, we can add an action that shows the custom component value in an Alert Dialog. This data can then be accessed easily, using built-in component states that retrieve data from the custom component. This approach can make it simpler to handle data management for custom components, by leveraging the capabilities of the FlutterFlow platform.

All easy, right?! πŸ™‚

The Black Box (Custom Widget)

Now we will implement the same functionality using a custom widget containing a text field. Of course, this is to whit the purpose of maintaining a simple example. By building a custom widget, we can add additional capabilities that are not available in the default FlutterFlow components.

But, when we try to access the data from our custom widget to assign the value to an action, we don’t have the same capabilities to easily retrieve the data. This is because the state of the custom widget is not directly accessible to the rest of the application.

While considering how to overcome this obstacle πŸ€”, I remembered a well-known design pattern commonly used in software development: The Singleton Pattern. This pattern has been used frequently in the development world, and it occurred to me that it might be a useful approach to solve my problem.

To make the state of the custom widget available for use throughout the application, we can leverage the Singleton pattern. The Singleton pattern ensures that there is only one instance of a class in the entire application. This allows us to create a single instance of the custom widget, and access its state data from any other part of the application. With this approach, we can maintain the flexibility of building custom widgets with unique capabilities, while still being able to access and share their state data with the rest of the application.

In our case, sharing state means creating a bridge between our custom widget and the FlutterFlow platform. We want to enable our custom widget to pass its state data to the rest of the application that is built using FlutterFlow. In this way, we can take advantage of the benefits of both our custom widget and the FlutterFlow platform, while overcoming the obstacle of sharing state data between the two.

You might be wondering β€œWhy do I need to use the Singleton pattern?”. The simple answer is that a class can have multiple instances by default. For that reason, we can have multiple instances of the state, and if on different parts of the application may access different instances, which may not have the latest state data of our Custom Widget.

By using the Singleton pattern, we ensure that there is only one instance of the State in the entire application, and therefore all parts of the application can access the same instance and its latest state data.

Okay enough theory, for now, let's go through the code.

The Share State of the Custom Widget (Singleton Class)

Let's implement the class that represents the shareable state of our custom widget using the Singleton pattern to ensure that only one instance of the class exists in the entire application. This will allow us to share the state data of the custom widget with other parts of the application.

To implement the Singleton pattern, we create a class with a private constructor that prevents external instantiation. We also create a static method that provides access to a single instance of the class. This static method creates the instance if it doesn't exist, and returns the existing instance otherwise. With this approach, we can ensure that there is only one instance of the class throughout the application.

In the context of our custom widget, the Singleton class will hold the state data of the custom widget and provide a way to access and update the data from other parts of the application. We can implement the Singleton class using a simple code like this:

We can define the shared state singleton class in the same file as the custom widget, before the declaration of our custom widget.

The custom widgets that are generated by FlutterFlow are stateful widgets and are composed of two classes: the Widget class and the State class. In the State class, we need to add a new attribute that represents our singleton ShareableState class to access it.

Now, we need to set the value of the text field to our singleton Shared State. For our example, the simplest way is to use the onChanged method of our TextField widget (This method is executed every time a character adds or deletes from the text field):

And with that, we finished, and we can share the value throughout the application! Time to celebrate πŸ₯³... well not quite yet, I've encountered another problem 😣. FlutterFlow doesn't know anything about my Singleton class πŸ€¦πŸ»β€β™‚οΈ, which is necessary to share the state of my custom widget. But don't worry, the custom actions of FlutterFlow are here to the rescue.

FlutterFlow knows very well about custom actions, and we can define a custom action that returns the value of the shared state efficiently. We need to define a custom action that returns a String that is held by the Shareable state class.

Let's go to implement our custom action and the code looks like this:

You can see we are accessing the shared state instance and getting his value and returned from our custom action to pass the value to FlutterFlow.

Now, in the actions of the button of the main page, we can call our custom action and access the value of the shared state, and use it in the subsequent actions defined.

And in the Alert Dialog Action, we can take the value from the output of our custom action.

And with all the parts assembled, our application is done.

In this tutorial, we learned how to use the Singleton pattern to share the state of a custom widget throughout the FlutterFlow application. We saw how, by defining a Singleton class, we can ensure that only one class instance exists and is accessible from different parts of the app. We then integrated the Singleton class with a custom widget containing a text field and showed how to set and get the value of the text field through the Singleton instance. Finally, we used a custom action in FlutterFlow to access the shared state and perform subsequent actions. By following this approach, we can build more complex custom widgets and share their state safely and reliably.

Remember, I have used this approach in my 'Uploady' component for the FlutterFlow contest. Although it was a bit more complicated than what we have done in this example, the same principle was applied. By the way, my component won 3rd place in the contents competition 😎. I invite you to check it out here.

And of course, here of our example application where you can clone and review on detail the code. This is my first tutorial and all suggestion and improvement are welcome.

This article was originally posted on the Flutterflow Community blog

Interested in a free app review?

Schedule a call

Starting a new project or want to chat with us?

Subscribe