[Flutter]Manage state by linking Firestore and Redux
Overview
In a smartphone app that handles user data, I would like to write about how to link the state management while using the app with the external storage for data storage.
Specifically, redux is used for state management within the app, and cloud firestore is used for data storage (this is just an example, and there are other options).
Method
Overview
Data is stored in the firestore for each user.
When user A launches the smartphone app, sign in using a google account
After successful authentication of google account, get user A's data from firestore and store it in redux stroe
If user change the data, change the data on the firestore with the redux middleware
Firestore configuration
Create a "users" collection in the firestore and stores each user's data as a document. The document id is a google account.
Login and authemtification
When the app starts, the login page prompts the user for a google account. Authenticate using firebase auth, and if authentication is successful, get the user data of that gmail address from firestore.
For example, the process to get the user's data from the firestore from the User instance of firebase auth is as follows.
Future<AppState> get_data(User user)async{
FirebaseFirestore db;
DocumentReference docRef;
CollectionReference colRef;
//initialize firestore instance
db=FirebaseFirestore.instance;
//Get a reference to the user's data with a gmail address
colRef=await db.collection('users');
docRef=await colRef.doc(user.email);
var snapshot=await docRef.get();
if (!snapshot.exists){
//If the user data does not exist, add a new one
await colRef.doc(user.email).set({'name': user.displayName});
docRef=await colRef.doc(user.email);
}
//Get data from reference and store in map
var col_items
=await docRef.collection('items').get();
Map<int, String>items={};
for(var snapshot in col_items.docs){
int id=int.parse(snapshot.id);
items[id]=snapshot.data()['item'];
}
return AppState(items: items);
}
As an example, I assumed the case of int type id and String type data (item) map.
class AppState{
Map<int, String> items;
AppState({this.items});
AppState.initState(){
items={};
}
}
Store in store
Initialize the store using the data obtained above.
There is also a method of initializing with empty data and then retrieving the data with middleware (or maybe that is better).
AppState state;
try {
state = await fireStore.initDataSets(user);
}
catch(Exception){
state=AppState.initState();
}
Store<AppState> store=Store<AppState>(
appStateReducer,
initialState: state,
middleware: [AppStateMiddleWare]
);
Reflect data changes in firestore
Pass a reference to the firestore's user's document to action, and midlleware will use that reference to write to the firestore. In the above get_data, the reference is stored in a local variable, but it may be convenient to make it a class member.
middleware
void AppStateMiddleWare(Store<AppState> store, dynamic action,
NextDispatcher next) async {
next(action);
if (action is AddItemAction){
var docRef=action.docRef;
int id=action.id;
await docRef.collection('items')
.doc(id.toString()).set({'item': action.item});
}
}
action
class AddItemAction{
final String item;
final int id;
final DocumentReference docRef;
AddItemAction({this.item, this.id, this.docRef});
}
Lastly
I think there are quite a lot of uses like this, but I don't see any methodology at all, so I wrote it. It is used only for personal development, so please use it as a reference only.
Recent Posts
See AllWhat want to do I want to create an input form using TextField. For example, if the input content is a monetary amount, I would like to...
What want to do There is a variable that remain unchanged once the initial value is determined. However, it cannot be determined yet when...
What want to do As the title suggests. Place two widgets in one line on the screen One in the center of the screen and the other on the...
Comments