|
| 1 | +--- |
| 2 | +title: FFAppState |
| 3 | +--- |
| 4 | + |
| 5 | +# FFAppState |
| 6 | + |
| 7 | +The `FFAppState` class in FlutterFlow acts as a central hub for managing the application's global state. It's designed as a singleton, meaning there's only one instance of this class throughout the app's lifecycle. This class extends [**ChangeNotifier**](https://api.flutter.dev/flutter/foundation/ChangeNotifier-class.html), allowing widgets to listen and react to state changes. |
| 8 | + |
| 9 | +It includes methods for initializing and updating the app's persisted state and also defines various state variables with corresponding getters and setters for manipulating these values. |
| 10 | + |
| 11 | +Here is a basic template of the class, taken from the eCommerce app's generated code: |
| 12 | + |
| 13 | +```js |
| 14 | +class FFAppState extends ChangeNotifier { |
| 15 | + static FFAppState _instance = FFAppState._internal(); |
| 16 | + |
| 17 | + factory FFAppState() { |
| 18 | + return _instance; |
| 19 | + } |
| 20 | + |
| 21 | + FFAppState._internal(); |
| 22 | + |
| 23 | + static void reset() { |
| 24 | + _instance = FFAppState._internal(); |
| 25 | + } |
| 26 | + |
| 27 | + void update(VoidCallback callback) { |
| 28 | + callback(); |
| 29 | + notifyListeners(); |
| 30 | + } |
| 31 | + |
| 32 | + // App State variable of primitive type with a getter and setter |
| 33 | + bool _enableDarkMode = false; |
| 34 | + |
| 35 | + bool get enableDarkMode => _enableDarkMode; |
| 36 | + |
| 37 | + set enableDarkMode(bool value) { |
| 38 | + _enableDarkMode = value; |
| 39 | + } |
| 40 | + |
| 41 | +} |
| 42 | +``` |
| 43 | + |
| 44 | +The `_enableDarkMode` is an App State variable created by developer that creates its own corresponding getter and setter. |
| 45 | + |
| 46 | +## Updating FFAppState |
| 47 | +When updating the FFAppState from the Action Flow Editor, you will be presented with several **[update type](../resources/data-representation/app-state.md#update-type)** options such as **Rebuild All Pages**, **Rebuild Current Page**, and **No Rebuild**. Let's see how the generated code changes when these options are selected. |
| 48 | + |
| 49 | +### Rebuild Current Page |
| 50 | +When a developer chooses to update App State with the update type set to **Rebuild Current Page**, the corresponding `setter` is called. Immediately after, `setState((){});` is invoked, which updates only the current page. |
| 51 | + |
| 52 | +Here's an example of the generated code when we update the App State `enableDarkMode` in the `onInitialization` action trigger of the `ProductListPage`. |
| 53 | + |
| 54 | +```js |
| 55 | +SchedulerBinding.instance.addPostFrameCallback((_) async { |
| 56 | + FFAppState().enableDarkMode = !(FFAppState().enableDarkMode ?? true); |
| 57 | + setState(() {}); |
| 58 | +}); |
| 59 | +``` |
| 60 | +
|
| 61 | +### Rebuild All Pages |
| 62 | +
|
| 63 | +In this case, the update type is set to **Rebuild All Pages**, meaning that the `setter` is called, followed by the `update()` method. This method internally calls `notifyListeners()`, which is crucial for updating any widgets that depend on this variable. |
| 64 | +
|
| 65 | +```js |
| 66 | +SchedulerBinding.instance.addPostFrameCallback((_) async { |
| 67 | + FFAppState().enableDarkMode = !(FFAppState().enableDarkMode ?? true); |
| 68 | + FFAppState().update(() {}); |
| 69 | +}); |
| 70 | +``` |
| 71 | +
|
| 72 | +:::tip[Updating App State from Custom Code] |
| 73 | +When updating App State variables from custom code, such as Custom Actions, it's crucial to call the update function to ensure that the changes are reflected across all pages. For example, you should use: |
| 74 | +
|
| 75 | +```js |
| 76 | +FFAppState().update(() => FFAppState().enableDarkMode = !(FFAppState().enableDarkMode ?? true)); |
| 77 | +``` |
| 78 | +::: |
| 79 | +
|
| 80 | +### No Rebuild |
| 81 | +Only the setter is called with no setState or update method invoked afterward. This means that only the variable is updated, with no state changes occurring after the data update. |
| 82 | +
|
| 83 | +## watch\<FFAppState\> |
| 84 | +
|
| 85 | +When you add an [**Update App State**](../resources/data-representation/app-state.md#update-app-state-action) action via the Action Flow Editor, the corresponding pages will include this line within the build method: |
| 86 | +
|
| 87 | +```js |
| 88 | + @override |
| 89 | +Widget build(BuildContext context) { |
| 90 | + context.watch<FFAppState>(); |
| 91 | + ... |
| 92 | +``` |
| 93 | +By using `context.watch<FFAppState>()`, the widget effectively subscribes to any changes in the `FFAppState` class. Whenever there's a change in the `FFAppState` object, this widget automatically rebuilds to reflect those changes. This ensures that your widget always displays the most current data and state of the app, maintaining an up-to-date and responsive user interface. |
| 94 | +
|
| 95 | +## Managing AppState\<List\> |
| 96 | +When you add an App State variable of `List` type in FlutterFlow, several utility functions are automatically generated to help you manage this list. These functions include a getter, a setter, and methods for adding, removing, and updating items in the list. This setup ensures that you can easily interact with the list while keeping the app state consistent and responsive. Below is an explanation of these generated functions using the specific example of a LatLngList. |
| 97 | +
|
| 98 | +```js |
| 99 | + |
| 100 | +late LoggableList<LatLng> _LatLngList = |
| 101 | + LoggableList([LatLng(37.4071594, -122.0775312), LatLng(40.7358633, -73.9910835)]); |
| 102 | + |
| 103 | +List<LatLng> get LatLngList => _LatLngList?..logger = () => debugLogAppState(this); |
| 104 | + |
| 105 | +set LatLngList(List<LatLng> value) { |
| 106 | + if (value != null) { |
| 107 | + _LatLngList = LoggableList(value); |
| 108 | + } |
| 109 | + |
| 110 | + debugLogAppState(this); |
| 111 | +} |
| 112 | + |
| 113 | +void addToLatLngList(LatLng value) { |
| 114 | + LatLngList.add(value); |
| 115 | +} |
| 116 | + |
| 117 | +void removeFromLatLngList(LatLng value) { |
| 118 | + LatLngList.remove(value); |
| 119 | +} |
| 120 | + |
| 121 | +void removeAtIndexFromLatLngList(int index) { |
| 122 | + LatLngList.removeAt(index); |
| 123 | +} |
| 124 | + |
| 125 | +void updateLatLngListAtIndex( |
| 126 | + int index, |
| 127 | + LatLng Function(LatLng) updateFn, |
| 128 | +) { |
| 129 | + LatLngList[index] = updateFn(_LatLngList[index]); |
| 130 | +} |
| 131 | + |
| 132 | +void insertAtIndexInLatLngList(int index, LatLng value) { |
| 133 | + LatLngList.insert(index, value); |
| 134 | +} |
| 135 | +``` |
| 136 | +
|
| 137 | +These functions are automatically generated to provide a convenient and consistent way to manage list-type App State variables, making it easier to maintain the app's state: |
| 138 | +
|
| 139 | +- The list `LatLngList` is initialized as a private variable `_LatLngList` of type `LoggableList`, which helps in managing the list with additional logging capabilities. |
| 140 | +- The get `LatLngList` method allows other parts of the app to access the `LatLngList`. |
| 141 | +- The set `LatLngList` method allows you to replace the entire `LatLngList` with a new one. When a new list is assigned, it updates the private variable `_LatLngList` and logs this change using `debugLogAppState`. |
| 142 | +- The `addToLatLngList` function appends a new `LatLng` object to the LatLngList, dynamically updating the list as the app runs. |
| 143 | +- The `removeFromLatLngList` function removes a specific `LatLng` object from the `LatLngList`, ensuring the list remains accurate and up-to-date. |
| 144 | +- The `removeAtIndexFromLatLngList` function removes a `LatLng` object from the list based on its index position. |
| 145 | +- The `updateLatLngListAtIndex` function allows you to update a `LatLng` object at a specific index by applying an update function (`updateFn`) to it. |
| 146 | +- The `insertAtIndexInLatLngList` function inserts a new `LatLng` object into the `LatLngList` at a specific index, shifting the existing items as necessary. |
| 147 | +
|
| 148 | +
|
| 149 | +
|
| 150 | +
|
| 151 | +:::info[How to create App State variables] |
| 152 | +To learn more about creating and using App State variables in FlutterFlow's UI, check out the[ **App State**](../resources/data-representation/app-state.md) guide. |
| 153 | +::: |
0 commit comments