So, I might be missing something, but everyone says ReactiveDict is better than Session when storing instance values. But, what about hashing? It doesn't seem as though reactiveDict can hide data like storing in the Session? I am able to get the data from the app through the console using reactiveDict... so, if I wanted to hide this instance data, wouldn't it make sense to use Session?
Thoughts?
appState = new ReactiveDict('appState')...;
Session.set(key, value)...
If you can see the source code for session package here https://github.com/meteor/meteor/blob/devel/packages/session/session.js
Session = new ReactiveDict('session');
Session is nothing but a ReactiveDict.
Reason why people say ReactiveDict is better than session is, Session is global, you can go to console and type Session.keys to get all the values.
Where as ReactiveDict has option to not make it global
if you want to use ReactiveDict in single file you can use like below
const appState = new ReactiveDict('appState')
.
.
.
appState.set('key', 'value');
.
.
.
appState.get('key');
here appState is not global.
If you want to use same across different files, you can use import and export like below
set.js
------
const appState = new ReactiveDict('appState')
appState.set('key', 'value');
.
.
.
export default appState
then
get.js
------
import appState from './set.js';
appState.get('key'); //result will be value'
So the advantage reactivedict has over session is, session is global where as reactivedict can be not global.
Related
Last year I spent some time learning Vue 2. I really enjoyed the framework but did not move forward with a project. I now have time for a project but I'd like to use Vue 3 with the composition API. I'll be using Firebase as the backend. I've seen conflicting techniques on whether or not to use Vuex.
For example, I'd like to store a "currentUser" object in global state that can be accessed from any component in the app. Normally, it would be done using Vuex. I'd have a getter to return the object, an async action to get the data from firebase and a mutation to set the state.
However, I've seen several Vue 3 code examples that do not use Vuex at all, instead they do something like this to get/set a currentUser in an app wherever it is needed for example in a navbar component.
composables/getUser.js
import { ref } from 'vue'
import firebase from 'firebase/app'
// refs
const user = ref(firebase.auth().currentUser)
// auth changes
firebase.auth().onAuthStateChanged(_user => {
console.log('User state change. Current user is:', _user)
user.value = _user
});
const getUser = () => {
return { user }
}
export default getUser
With this little bit of code above, I'm able to import getUser.js and access the currently logged in user using code like this. Also, the user object is now reactive:
<script>
import getUser from '../composables/getUser'
export default {
setup() {
const { user } = getUser()
return { user }
}
}
</script>
It seems I can use these little functions to get data from db directly without the need to use the Vuex pattern, which I find to be a bit more complicated.
So, my question is - if I'm starting a new Vue 3 project, is it ok to create "composable" functions to get/set data and import them into my components instead of using Vuex? Are there any downsides to this method? Or should I just stick with Vuex?
Short answer - You don't need it.
Long answer - It depends.
It depends mostly on your app and how often do you use "currentUser" data inside your components. If it's in 2 or more components, how often do you want to perform actually fetching from backend?
Once on app-init/login or every time each component mounts?
(probably once)
Does it need to be reactive? If yes - then you'll probably use centralized data pattern, your own or a library. Taken that into consideration it's probably more simple to just use Vuex.
Scenario: You want to put the build id in the footer of a meteor app. The client will need a reference to process.env.BUILD_ID from the server.
Common answer: Save it in a collection. On meteor start, save the current build id to a collection and load that on the client.
Problem with the common answer: What if you have multiple containers running? Say for instance you're using kube to update the version. You have version abc running, and then kube starts pushing up def. In the process of starting each def container, it sets the current version in the db to def. Yet the abc containers are still running. If you hit one of those containers, it will report def as the build id. Even though thats wrong. Additionally, what if the kube update fails, and you decide to cancel the push to the new version and keep the old containers running. Until the next container restart, youll be serving the abc content but telling the user its version def.
What would be the proper way to store a constant and match it on the client without lying about its true value?
Meteor methods are the way to get data from the server (as opposed to the using publications to get from the database). I recommend using ValidatedMethod for extra modularity and nicer validation.
Define the following method in your project and make sure it is imported to the server on server startup:
import { Meteor } from 'meteor/meteor';
import { ValidatedMethod } from 'meteor/mdg:validated-method';
const getAppVersion = new ValidatedMethod({
name: 'getAppVersion',
validate: null,
run({}) {
return process.env.BUILD_ID;
},
});
export default getAppVersion;
Then in the frontend code:
import getAppVersion from '/imports/api/methods/getAppVersion.js';
getAppVersion.call({}, (err, res) => {
if (res) setFooterVersion(res);
});
You can throw it in a store:
// in store.js
export default const store = {
buildId: '',
};
// then in buildId.js:
import store from './store';
Meteor.call('getBuildId', (res, err) => store.buildId = res);
// in someplace like server/methods.js:
Meteor.methods({
'getBuildId'() {
return process.env.BUILD_ID;
},
});
// then, anywhere you need the build id:
import store from './store';
store.buildId; // outputs build id
If you need to make it reactive, you can make the store object a ReactiveDict, then put the Meteor.call part within Tracker.autorun for what you want it to react to. You can alternatively put it in something like a setInterval to run every 10 minutes or so. Of course, you can always store it in the db too -- but for your scenario, you can try to create an additional column like kubeNode and pass in the server id from kubernetes into the db, so when you call it again, you call it with a reference to the appropriate k8s node.
I am building an mobile app using Ngrx and Angular2. I would like to clear the Store when user logout from my application? Can anyone know how to do this?
You should have an clear action in each of your reducer, which will clean respective properties in the store. Dispatch clear actions in each of the reducer manually when you call logout. I am not sure right now if its there an option to clean the entire store in one go.
Alternative:
A more cleaner and faster approach would be. Whenever you call an action via store.dispatch it calls all your reducers with that action.type. Say your action type name is CLEAR, put this action in each of your reducer to clear the respective property of the store. And call store.dispatch with action.type = 'CLEAR' ONCE, it will clear all the properties of the store.
If it confuses let me know, I will try to explain with code.
The solution is to write the root reducer.
It's similar to this:
export function reducer(state: any, action: any): ActionReducer<any> {
if (action.type === 'CLEAR STATE') {
state = undefined;
}
return appReducer(state, action);
}
Check this: How to reset the state of a Redux store?
My guess as to a way to do this would be to have a component that has the store registered on it. Put it in a router-outlet or a structural directive that could force a destroy and init on the component when the value changes.
Since the store is registered as a provider for the component (unless I'm mistaken) and should be tied to it, it should be destroyed when the component is destroyed and a new one created with a new component. Just a thought. I haven't had time to test it.
Don't register the provider in a parent component though. I believe the injectables work through a hierarchy.
I have the following code:
sub_geo = Meteor.subscribe('geo');
console.log('sub_geo returned from Meteor.subscribe: ');
console.log(sub_geo);
Session.set('sub_geo', sub_geo);
console.log('sub_geo retrieved from Session: ');
console.log(Session.get('sub_geo'));
The output is as follows:
sub_geo returned from Meteor.subscribe:
> Object {stop: function, ready: function}
sub_geo retrieved from Session:
> Object {}
Obviously I need to store the returned subscription handle because I need to call the ready() and stop() functions on it later. Not sure how else to store it other than in the Session. Can I just use a global variable? Also - even if there is some other way of doing it, why doesn't this approach work?
It doesn't work because you can only store EJSON-serializable objects in session variables. If you need the subscription handle outside of the current file, you'll need to store it in a global variable (perhaps under a namespace like Subscriptions - e.g. see richsilv's answer to this question.
You can actually do this, but not the way you would expect.
Just set the Session as you do:
Session.set('sub_geo', sub_geo);
Then when you want to do something with your subscription, retrieve the handle from Meteor's own registry:
const handle = Meteor.default_connection._subscriptions[Session.get('sub_geo').subscriptionId]
And if you ARE going to use the Session (which is not encouraged, except if you really have to), clean it up:
delete Session.keys['sub_geo'];
This is working fine in Meteor 1.3.3.1 for me at the moment, but probably will work for most previous versions as well.
PS: Alternatives for Session are Reactive Var and Reactive Dict.
I am new to enyo. I want to save a state of variable (which is boolean) while app executes. Then exit the app. After that I want to get the state (true/false) of the variable when app re-opens. How to save and restore the data in enyo?
I would use localStorage (API Docs here) to save your state every time the change in state occurs in your application:
myStateChange: function() {
localStorage.myState = this.myState;
}
Note: to ensure that myStateChange is called every time you set it elsewhere, use this.set() method to set it, not this.myState = newValue;.
Then, in rendered() or create() method I would restore that state from localStorage.
rendered: function() {
this.inherited(arguments); // Call base rendered method
this.myState = localStorage.myState; // Restore your saved value from localStorage
}
There are no special hooks for data storage but it's very easy to tie into the native data storage options available for your platform. You might take a look at these options:
http://dev.opera.com/articles/view/taking-your-web-apps-offline-web-storage-appcache-websql/
http://docs.phonegap.com/en/1.0.0/phonegap_storage_storage.md.html
If you're using enyo.Collection you can get the records from it with collection.raw() and then use JSON.stringify() to get something you can put into localStorage.
You could even use cookies. Hope that gives you some places to start looking from.