In my Windows Store App I store data directly in the sessionState object so I don't need to move data there later on. In one case I store an object that has accessor methods for variables that are declared in the containing scope like so:
(function ()
{
var a = [];
var index = -1;
WinJS.Application.sessionState.data =
{
add: function (item)
{
index = a.length;
a.push(item);
},
currentItem: function ()
{
return a[index];
}
};
})();
My question is if the sessionState object will store a and index since they're scope referenced or not since they're are not really in it.
You can use "data" to manipulate "a" and "index" until the first time your app was suspended. Any data stored in the sessionState object is automatically serialized to disk when your app is suspended. Functions will be removed. After resuming, we lost 2 functions "add" and "currentItem".
See more: http://msdn.microsoft.com/en-us/library/windows/apps/hh440965.aspx
Related
I know that if I want to add a property to a data object, I use Vue.set(). I did this in my created() lifecycle method ... a new field will be added to the myObject. But what about if I wanted to make an api call and completely replace the existing data object of myObject? Can I do what I am doing in updateMore() method or is there another way to handle this?
data() {
return {
myObject: {}
}
},
async created() {
let apiData = await axios.get('http://myurl.com');
this.$set(this.myObject, 'name', apiData.name);
},
methods: {
updateMore() {
let moreAPIData = await axios.get('http://myurl.com');
// will this completely override `myObject` with `moreAPIData` and still be reactive?
this.myObject = moreAPIData;
}
}
TL;DR:
This assignment of a new object is fine. Vue reactivity issues occurs when you add a new key to an object, because the object is the same, what changed was its content. Javascript compares objects by its address, so if I do
new MyClass() === new MyClass()
it returns false, because, even if they have the same content, they have different addresses.
To conclude, when you set a whole new object, Vue is able to track the difference, but when you change the content of one key, it can't.
Full boring text
You can read the whole documentation about reactivity in Vue here
I'm using react js with mobx and I get data from api.
the data I get is array of objects.
when I set the data into mobx variable then I see array of proxy objects(not sure what the proxy says). I'm trying just to set the array of objects I get from api into mobx variable.
my store
class UserStore {
#persist #observable token = null
#observable tasks = []
#observable done = false
#persist #observable email = ''
constructor() {
}
#action
getTasks = async () => {
try {
let response = await Api.getTasks()
console.log('getTasks',response.tasks)
this.tasks = response.tasks
console.log('my new tasks',this.tasks)
} catch (e) {
console.log(e)
}
}
as you can see here in the first block('black') the data i get from api, then i set the respnse.tasks into this.tasks.
this.tasks = response.tasks
console.log('my new tasks',this.tasks)
You can convert proxy to JS:
import { toJS } from 'mobx'
// example
toJS(response)
It depends on how you want to observe the data.
"I'm trying just to set the array of objects I get from api into mobx variable"
is not really your end-goal.
If you want your observers to:
option a: react when the array reference change
= No care for values in the array.
Use #observable.ref tasks.
option b: react when the references of each value in the array change
= No care for the individual objects properties.
Use #observable.shallow tasks.
option c: react on the individual objects properties too
= Make everything observable, references and object properties
Use #observable tasks like you do.
Like indicated in the comments, mobx5 is using Proxy and some behaviour might differ compared to previous version.
More info: Mobx arrays, Mobx decorators, shallow observability
Note: you would need to give more details if this does not help you, like your react component code.
In my case, toJS was not working because I had a class with a variable with the type of another class. So, I needed to create new objects from the JSON:
parsedArray.map(
(a) =>
new MyObj1({
id: a.id,
myObj2: new MyObj2({
label: a.label,
}),
title: a.title,
})
);
If you run debugger, stop the debugger. It messes the mobx's flow.
I'm wanting to fetch all items from a table into a collection but am getting an error that the table name is undefined. Here is my store:
db.version(1).stores({
users: '++id,',
orgs: '++id,',
applications: '++id'
})
Then later here is my call:
db.orgs.toCollection().count(function (count) {
console.log(count)
})
It gives the following error:
TypeError: Cannot read property 'toCollection' of undefined
But when I stop the debugger at the call and type in db.tables sure enough:
1:Table {name: "orgs", schema: TableSchema, _tx: undefined, …}
_tx:undefined
hook:function rv(eventName, subscriber) { … }
name:"orgs"
Any help is appreciated - thanks.
UPDATE
I noticed that when I seeded the database on initial creation I could fetch the data out. So I copied in that code into my template. It still fails however, so there must be something simple I'm missing, here is that code:
import Dexie from '#/dexie.es.js'
export default {
name: 'ListOrgs',
data: () => {
return {
orgs: []
}
},
methods: {
populateOrgs: async function () {
let db = await new Dexie('myDatabase').open()
db.orgs.toCollection().count(function (count) {
console.log(count)
})
}
},
mounted () {
this.populateOrgs()
}
}
Dexie has two modes
Static - the most common one used in most samples.
Dynamic - Schema is not specified in code.
Static Mode
//
// Static Mode
//
const db = new Dexie('myDatabase');
db.version(1).stores({myTable1: '++'});
db.version(2).stores({myTable1: '++, foo'});
db.myTable1.add({foo: 'bar'}); // OK - dexie knows about myTable1!
Dynamic Mode
//
// Dynamic Mode
//
const db = new Dexie('myDatabase');
// FAIL: db.myTable1.add({foo: 'bar'}); // myTable1 is unknown to the API.
// Here, you must wait for db to open, and then access tables using db.table() method:
db.open().then(db => {
const myTable = db.table('myTable');
if (myTable) {
myTable.add({foo: 'bar'});
}
}).catch(error => {
console.error(error);
});
If omitting any version() specification, Dexie will just try to open any existing database with the same name, no matter version or schema. But it won't create the implicit table properties onto the db instance.
When Dynamic Mode is Useful
Dynamic mode can be useful when building an arbritary database utility that should adapt to any indexedDB database - such as a DB explorer. Dynamic mode can also be useful when the javascript code is by design not aware of the schema (what tables are expected to be queried and what indexes there are).
Benefits with Static Mode
No need to wait for db.open() to complete.
Automatic DB creation when neeeded. No complex app code to deal with database versioning.
Automatic DB population when needed.
Design Patterns in Static Mode
db.js
import Dexie from 'dexie';
//
// Let this module do several things:
//
// * Create the singleton Dexie instance for your application.
// * Declare it's schema (and version history / migrations)
// * (Populate default data http://dexie.org/docs/Dexie/Dexie.on.populate)
//
export const db = new Dexie('myDatabase');
db.version(1).stores({
users: '++id,',
orgs: '++id,',
applications: '++id'
});
db.on('populate', () => {
return db.orgs.bulkAdd([
{'foo': 'bar'},
]);
});
app.js
import {db} from './db';
// Wherever you use the database, include your own db module
// instead of creating a new Dexie(). This way your code will
// always make sure to create or upgrade your database whichever
// of your modules that comes first in accessing the database.
//
// You will not have to take care of creation or upgrading scenarios.
//
// Let Dexie do that for you instead.
//
async function countOrgs() {
return await db.orgs.count();
}
In my component I am trying to get the old value and new value of a particular array of objects that is assigned in the vuex store state as followed. However when I newArray and oldArray return the same array of objects.
I understand from the documentation the following but I dont understand what is the best way to retrieve the different versions.
Note: when mutating (rather than replacing) an Object or an Array, the old value will be the same as new value because they reference the same Object/Array. Vue doesn’t keep a copy of the pre-mutate value.
here how I am trying to do it right now in the component
export default {
name: 'O1_OrderBook',
watch: {
'$store.state.orderBookSell': {
deep: true,
handler (newArray, oldArray) {
console.log(newArray,oldArray)
}
}
},
}
let say when you create an array/object in Javascript,
var arr = [1,2,3];
This creates an array in the browser's memory. But what arr variable contains is not the entire array value, it contains the reference to the array in browser memory. You could think of it as arr contains an address that can point you to the real array value in browser's memory.
if you do
var arr = [1,2,3];
var arr2 = arr;
arr2[0] = 4;
console.log(arr); // you would get [4,2,3];
editing arr2 changed arr too. Because they both point to the same array in browser memory.
That's what "the old value will be the same as the new value because they reference the same Object/Array" means.
The same principle applies to object as well. In Javascript, an array is just a special type of object.
to retrieve the different versions of the array in the watcher, you must clone it to set it as a new array everytime you mutate it.
for e.g.,
state.orderBookSell = [...state.orderBookSell];
BUT..... [...array] is shallow cloning, not deep cloning. And that's a problem. You have an array of objects. Remember that object also have the same rules. They are passed by reference. So you gotta do a deep clone, so that all the objects is cloned as well.
using lodash cloneDeep method for deep cloning
state.orderBookSell = _.cloneDeep(state.orderBookSell);
Based on Jacobs answer this is what I re-arranged in my component as to get it to work.
I created a computed variable in the component that deepClones the particular state array of objects.
computed: {
orders () {
return _.cloneDeep(this.$store.state.theArray)
},
},
and then setup a watch for that computed variable
watch: {
orders (newValue,oldValue) {
console.log(newValue,oldValue)
}
}
I'm trying to create an object in one part of vuex store, and then pass id to it to another object, and i'm not sure how to properly do that since mutations can't return returning anything (in this case, id).
Two store objects look like this:
// store/report.js
const state = {
name: 'Untitled Report',
subReportIds: []
};
// store/subReport.js
const state = { ... }
And i'd like this action to create blank report, then blank subreport, and then assign subreport id to newly created report. (subreports are independent entities, and can be used by multiple reports, hence different area in store)
const actions = {
createNewReport({ state, commit }) {
commit(mutationTypes.CREATE_NEW_REPORT)
// below doesn't work - i can't get return from mutation
let newSubreportId = commit(mutationTypes.ADD_NEW_SUBREPORT)
// if this worked, i'd then do something like
commit(mutationTypes.ADD_SUBREPORT_TO_REPORT, newSubreportId)
}
};
How can i achieve the above?
So best way to accomplish to me would be to dispatch actions instead of committing the mutations. If you look at the methods in Vuex source, commit only executes with no return (so is a void) and dispatch returns the value you return from the action (which is a function)
For my actions, i always return a promise so that i can compose them like you mention above. Here is an example.
fetchSomething ({ commit }) {
return mockApiGetIds()
.then(response => {
commit({
type: SOME_MUTATION,
ids: response
});
return response;
});
},
Disclaimer : I don't know if it is truely a good idea, but at least, it seems to work, and to me, it feels prettier than having to use actions and promises, or to generate the id in the action...
With your mutation, you can pass an argument. To return a value from a mutation (like a newly created id), I write it to a placeholder in that argument :
someMutation(state, arg){
//...
arg.out = {
status : "succeed"
}
}
//...
this.$store.commit('someMutation', arg);
if(arg.out !== "succeed") console.log("ERROR");