Restore the previous saved status into redux - redux

We're using redux and immutable objects on our redux store.
The scenario is that a user might dump the current store status into database and later the user might be able to restore it.
I'm a newbie to redux.
Is there any keywords to search for this kind of techniques?
We will try to dump the status into JSON format and reload it from database.

The key word is "persistence". There's dozens of existing libraries for persisting Redux state already - you can either try using them as-is, or look at how they work and implement some of the approaches yourself.
To actually persist the state, you'd normally either do it in a store subscription callback, or in a middleware. Then, as part of your app's setup process, retrieve the persisted state (from the server or localStorage or wherever you persisted it), and pass it as the second argument to createStore(rootReducer, preloadedState).

I have used window.localStorage for this.
const MyReducer = (state,action) => {
switch(action.type){
...
case 'SAVE_STATE':
stateString = JSON.stringify(state.toJS())
window.localStorage.setItem('applicationState', stateString)
return state
}
}

Related

Calling .setPersistenceEnabled(false) when logging out of app, not working

In my Flutter/Dart mobile app I make use of Firebase RTDB persistence to enable offline use of the app.
My understanding is that to enable persistence you have to make the call, as per the following piece of code, before using any database references to eg. query the database. I use the following piece of code to enable persistence immediately after loading the app and it works fine:
FirebaseDatabase firebaseDatabase = FirebaseDatabase.instance;
bool _success = await firebaseDatabase.setPersistenceEnabled(true);
print(_success); // Prints true, so persistence is set 'on'.
When I logout of the app I attempt to turn persistence off with:
bool _success = await firebaseDatabase.setPersistenceEnabled(false);
print(_success); // Prints false, so persistence is still 'on', ie. the call failed.
I assume the reason persistence cannot be turned off is because there have been calls to db references prior to trying to switch it off.
This leads to three questions, I guess:
Should I be worried about turning it off at all, when I logout? The reason I attempt it is good house-keeping, mainly. I clean up shared preferences, close keepsyncd's, etc when logout is run. Also, though, the user can have multiple userids to login and I want to make sure that I am not retaining persisted data from their previous login id.
Related to 1, does setting persistence to false clear the cache of
data and potential queued calls to the db?
If the answers to 1 and 2 are 'yes', how can I switch persistence off given the code I'm using to do so keeps telling me it failed?
The typical way to handle this is to enable persistence once a user logs in.
Once disk persistence has been enabled and your app has used the database, it cannot be turned off. The documentation says this about it:
The returned Future will complete with true if the operation was successful or false if the persistence could not be set (because database references have already been created).
That last bit is clearly the case for you: you've been using the database already, which means that disk persistence is on.
To your specific questions:
Unfortunately the data in the local cache cannot be cleared up through the API at the moment. It is a valid feature request, but for now you'll have to assume that any data on the device can be seen by any user on that device (or device profile).
Disabling disk persistence keep the client from adding data to the cache. It does not clear any existing data in the cache.

cache queries with firestore

I know I can add { source: "cache" } to read from the cache
but in this case what I need is to persist data on the server
export const getPeople = () => {
return db
.collection("cities")
.doc("SF")
.collection("people")
.get();
};
every user hitting the site will run that query. I want to cache for a few minutes at least. is there a way to do it?
The client API will not conditionally cache for you. Either it uses the cache, or it does not. (The only condition it applies is falling back to the cache if there is no network connectivity.)
What you can do instead is implement your own cache on top of the API, which is non-trivial to do. Even an in-memory cache will require you to implement the logic of checking to see if a cached snapshot is within whatever time bounds are acceptable without a refresh.

Redux - Where to keep non-serializable Data?

Suppose, i want to keep some non-serializable data for my applciation, which the user can access and interact with across the application. So for example, a connected device (bluetooth, wlan), a media stream, something of this sort. Im wondering where to put such data, when using the Redux paradigm?
Pseudocode:
A normal lifecycle of a subscription might look like this:
Subscription connection = instance.connect(device, request).listen();
...
connection.send(data);
...
data = connection.read();
...
connection.unsubscribe();
the app store might look like this:
Store:
{
username: '',
friends:[], <--- Pulled from the server with async middleware
connections:[], <--- Connections data here ???
}
But I would go on and say, that such a device subscription or media stream is not serializable and therefore it would be not proper, to hold them in the Redux Appstate.
And i'm aware, that for example for server request, one is encouraged to use middleware. So for friends of the user, one would write asynchronous actions to pull the friends user names from the server at the login of a user. But a device id in the state wont do, since one has to actually interact with the device connection stream in the app.
So would writing a seperate middleware be an acceptable way to hold on to such data? What is the common practice herefore?

Meteor signaling without db write

I've been looking for a good way to do, but haven't found anything that doesn't seem hacky. I want to signal the client without going through the database and a subscription. For example, in a game I want to send a message to the client to display "Player 1 almost scores!". I don't care about this information in the long run, so I don't want to push it to the DB. I guess I could just set up another socket.io, but I'd rather not have to manage a second connection if there is a good way to go it within meteor. Thanks! (BTW, have looked at Meteor Streams, but it appears to have gone inactive)
You know that Meteor provides real-time communication from the server to clients through Publish and Subscribe mechanism, which is typically used to send your MongoDB data and later modifications.
You would like a similar push system but without having to record some data into your MongoDB.
It is totally possible re-using the Meteor Pub/Sub system but without the database part: while with Meteor.publish you typically return a Collection Cursor, hence data from your DB, you can also use its low-level API to send arbitrary real-time information:
Alternatively, a publish function can directly control its published record set by calling the functions added (to add a new document to the published record set), changed (to change or clear some fields on a document already in the published record set), and removed (to remove documents from the published record set). […]
Simply do not return anything, use the above mentioned methods and do not forget calling this.ready() by the end of your publish function.
See also the Guide about Custom publications
// SERVER
const customCollectionName = 'collection-name';
let sender; // <== we will keep a reference to the publisher
Meteor.publish('custom-publication', function() {
sender = this;
this.ready();
this.onStop(() => {
// Called when a Client stops its Subscription
});
});
// Later on…
// ==> Send a "new document" as a new signal message
sender.added(customCollectionName, 'someId', {
// "new document"
field: 'values2'
});
// CLIENT
const signalsCollectionName = 'collection-name'; // Must match what is used in Server
const Signals = new Mongo.Collection(signalsCollectionName);
Meteor.subscribe('custom-publication'); // As usual, must match what is used in Server
// Then use the Collection low-level API
// to listen to changes and act accordingly
// https://docs.meteor.com/api/collections.html#Mongo-Cursor-observe
const allSignalsCursor = Signals.find();
allSignalsCursor.observe({
added: (newDocument) => {
// Do your stuff with the received document.
}
});
Then how and when you use sender.added() is totally up to you.
Note: keep in mind that it will send data individually to a Client (each Client has their own Server session)
If you want to broadcast messages to several Clients simultaneously, then the easiest way is to use your MongoDB as the glue between your Server sessions. If you do not care about actual persistence, then simply re-use the same document over and over and listen to changes instead of additions in your Client Collection Cursor observer.
It's completly fine to use the database for such a task.
Maybe create a collection of "Streams" where you store the intended receiver and the message, the client subscribe to his stream and watches any changes on it.
You can then delete the stream from the database after the client is done with it.
This is a lot easier than reinventing the wheel and writing everything from scratch.

What is the best practice to save access token in react-native app with redux?

What is the best practice to save access token in react-native app with redux?
In Redux, I used to save the whole credential, including some user information to the state:
//Actions
export const successfulLogin = (firebaseAuth) => ({
type: 'LOGIN_SUCCESSFUL',
firebaseAuth
});
//Reducer
const authentication = (state = {}, action) => {
switch (action.type) {
case 'LOGIN_SUCCESSFUL':
return {
...state,
firebaseAuth: action.firebaseAuth
};
default:
return state;
}
}
export default authentication
After that, I found a new module redux-persist, which helps me to save the state to device storage, localStorage. However, everything in the store will be saved. Is it a good practice to save access token with redux-persist?
If not, what should I use?
I think what you're describing works, but it's a bit overkill to save the entire store if you only need one access token. Therefore I'd say it's best practice to accomplish exactly what you need with a bit of code.
As an alternative to using redux-persist you can just do this side effect handling yourself:
Read the access token from localStorage when redux' createStore is called and pass it into the preloaded state. Or..
Dispatch an action like SET_ACCESS_TOKEN to add the token to the redux store at a later point.
To save the token right after successful login, you can trigger a side effect (calling a module that is responsible for writing something to localStorage) in the respective async action creator.
That's it, no additional modules necessary.
It's been a while since this question was asked but with redux-persist you don't need to save the entire store. You can provide keys that you want to store and it will ignore keys that you have not specified.

Resources