Storing class instances in recoil - recoiljs

we're trying to store a class instance as an atom state value. When we get the state value we'd like to copy and then mutate the object by calling methods on it. The code looks something like this:
const [config, setConfig] = useRecoilState<ConfigClass>(configAtom);
const updateConfig = () => {
const updatedConfig = _.cloneDeep(config);
updatedConfig.setProperty1('A');
updatedConfig.setProperty2('B');
setConfig(updatedConfig);
}
...
The problem here is that doing this results in TypeScript errors such as
TypeError: attempted to get private field on non-instance
It seems the config value received from the useRecoilState isn't a normal instance of the class. How can I get around this?

You cannot store a function/instance in a recoil state, all recoil states should be of type object notation (without functions), bool, number, strings and others, basically any data type serializable or able to convert to JSON.

Related

reference vue instance in mapState function

Is there a way in Vue2 to do this:
....,
computed {
...mapState('myModule', {
myVal: (state, vm) => state.someVar.filter((_) => { return vm.someVar })
})
},
....
The actual function I'm working on is filtering the state.someVar in a more complex scenerio, so this is simplified. The point being that this is undefined.
Anyone know how to reference the vue in such a function?
The 2nd argument to the mapState function is supposed to be a state mapper (array or object)
If you are using an object (as you are), you can only set the properties of the object to the keys in your "myModule" state object. You cannot set them as functions
e.g {customName: moduleStateKey}
As for passing component instance, you can only do that in an action or mutation. However, that would make your store impure. It would be better to pass someVar to state via a mutation fired from the component, then use a getter for the filter logic and use the someVar passed to state there

What is the difference between ref, toRef and toRefs

I have just started working with Vue 3 and Composition API.
I was wondering what are the differences between ref, toRef and toRefs?
Vue 3 ref
A ref is a mechanism for reactivity in Vue 3. The idea is to wrap a non-object inside a reactive object:
Takes an inner value and returns a reactive and mutable ref object. The ref object has a single property .value that points to the inner value.
Hmm.. Why?
Vue 3 relies on JavaScript proxies to detect changes to your reactive data and implement the reactivity. Proxies are essentially event listeners for objects: any reading or writing on a proxied object triggers the proxy, which can then do something with the values. This is convenient for reactivity since the variable changing will provide a trigger from which Vue can update any dependencies.
But proxies require objects to work. So Vue provides the ref method to convert your non-object variables into objects and then to grant reactive capabilities through a proxy. (Objects are reference variables, hence the name ref.)
(And Vue automatically unwraps your refs in the template, which is an added benefit of ref that you wouldn't get if you wrapped your value variables in an object manually.)
reactive
If your original variable is already an object (or array), a ref wrapping is not needed because it is already a reference type. It only needs Vue's reactive functionality (which a ref also has):
const state = reactive({
foo: 1,
bar: 2
})
But now consider copying a property from the object above to a new variable, for example foo which contains the number 1. If you copied this to a new variable, the copy would of course be a regular, non-reactive variable having no connection to the reactive object it was copied from. If foo changed later, the copy would not, meaning the copy is not reactive. This is where toRef is useful.
toRef
toRef converts a single reactive object property to a ref that maintains its connection with the parent object:
const state = reactive({
foo: 1,
bar: 2
})
const fooRef = toRef(state, 'foo')
/*
fooRef: Ref<number>,
*/
Now if state.foo changes, fooRef.value will change as well. So toRef has enabled copying a value property in such a way that the copy also has a reactive connection to the original parent object.
toRefs
toRefs converts all of the properties, to a plain object with properties that are refs:
const state = reactive({
foo: 1,
bar: 2
})
const stateAsRefs = toRefs(state)
/*
{
foo: Ref<number>,
bar: Ref<number>
}
*/
When would I ever use toRef or toRefs?
The most likely time would be when importing a reactive object, say from a composable, and destructuring it. The act of destructuring will pull the current property value from the object into a new local variable that will not be reactive without toRef. You may notice this when importing and destructuring a Pinia store into your component, for example.
reactive
reactive creates a deeply reactive proxy object based on a given object. The proxy object will look exactly the same as the given, plain object, but any mutation, no matter how deep it is, will be reactive - this includes all kinds of mutations including property additions and deletions. The important thing is that reactive can only work with objects, not primitives.
For example, const state = reactive({foo: {bar: 1}}) means:
state.foo is reactive (it can be used in template, computed and watch)
state.foo.bar is reactive
state.baz, state.foo.baz, state.foo.bar.baz are also reactive even though baz does not yet exist anywhere. This might look surprising (especially when you start to dig how reactivity in vue works). By state.baz being reactive, I mean within your template/computed properties/watches, you can write state.baz literally and expect your logic to be executed again when state.baz becomes available. In fact, even if you write something like {{ state.baz ? state.baz.qux : "default value" }} in your template, it will also work. The final string displayed will reactively reflect state.baz.qux.
This can happen because reactive not only creates a single top level proxy object, it also recursively converts all the nested objects into reactive proxies, and this process continues to happen at runtime even for the sub objects created on the fly. Dependencies on properties of reactive objects are continuously discovered and tracked at runtime whenever a property access attempt is made against a reactive object. With this in mind, you can work out this expression {{ state.baz ? state.baz.qux : "default value" }} step by step:
the first time it is evaluated, the expression will read baz off state (in other words, a property access is attempted on state for property baz). Being a proxy object, state will remember that your expression depends on its property baz, even though baz does not exist yet. Reactivity off baz is provided by the state object that owns the property.
since state.baz returns undefined, the expression evaluates to "default value" without bothering looking at state.baz.qux. There is no dependency recorded on state.baz.qux in this round, but this is fine. Because you cannot mutate qux without mutating baz first.
somewhere in your code you assign a value to state.baz: state.baz = { qux: "hello" }. This mutation qualifies as a mutation to the baz property of state, hence your expression is scheduled for re-evaluation. Meanwhile, what gets assigned to state.baz is a sub proxy created on the fly for { qux: "hello" }
your expression is evaluated again, this time state.baz is not undefined so the expression progresses to state.baz.qux. "hello" is returned, and a dependency on qux property is recorded off the proxy object state.baz. This is what I mean by dependencies are discovered and recorded at runtime as they happen.
some time later you change state.baz.qux = "hi". This is a mutation to the qux property and hence your expression will be evaluated again.
With the above in mind, you should be able understand this as well: you can store state.foo in a separate variable: const foo = state.foo. Reactivity works off your variable foo just fine. foo points to the same thing that state.foo is pointing to - a reactive proxy object. The power of reactivity comes from the proxy object. By the way, const baz = state.baz wouldn't work the same, more on this later.
However, there are always edge cases to watch for:
the recursive creation of nested proxies can only happen if there is a nested object. If a given property does not exist, or it exists but it is not an object, no proxy can be created at that property. E.g. this is why reactivity does not work off the baz variable created by const baz = state.baz, nor the bar variable of const bar = state.foo.bar. To make it clear, what it means is that you can use state.baz and state.foo.bar in your template/computed/watch, but not baz or bar created above.
if you extract a nest proxy out to a variable, it is detached from its original parent. This can be made clearer with an example. The second assignment below (state.foo = {bar: 3}) does not destroy the reactivity of foo, but state.foo will be a new proxy object while the foo variable still points the to original proxy object.
const state = reactive({foo: {bar: 1}});
const foo = state.foo;
state.foo.bar = 2;
foo.bar === 2; // true, because foo and state.foo are the same
state.foo = {bar: 3};
foo.bar === 3; // false, foo.bar will still be 2
ref and toRef solve some of these edge cases.
ref
ref is pretty much the reactive that works also with primitives. We still cannot turn JS primitives into Proxy objects, so ref always wraps the provided argument X into an object of shape {value: X}. It does not matter if X is primitive or not, the "boxing" always happens. If an object is given to ref, ref internally calls reactive after the boxing so the result is also deeply reactive. The major difference in practice is that you need to keep in mind to call .value in your js code when working with ref. In your template you dont have to call .value because Vue automatically unwraps ref in template.
const count = ref(1);
const objCount = ref({count: 1});
count.value === 1; // true
objCount.value.count === 1; // true
toRef
toRef is meant to convert a property of a reactive object into a ref. You might be wondering why this is necessary since reactive object is already deeply reactive. toRef is here to handle the two edge cases mentioned for reactive. In summary, toRef can convert any property of a reactive object into a ref that is linked to its original parent. The property can be one that does not exist initially, or whose value is primitive.
In the same example where state is defined as const state = reactive({foo: {bar: 1}}):
const foo = toRef(state, 'foo') will be very similar to const foo = state.foo but with two differences:
foo is a ref so you need to do foo.value in js;
foo is linked to its parent, so reassigning state.foo = {bar: 2} will get reflected in foo.value
const baz = toRef(state, 'baz') now works.
toRefs
toRefs is a utility method used for destructing a reactive object and convert all its properties to ref:
const state = reactive({...});
return {...state}; // will not work, destruction removes reactivity
return toRefs(state); // works

Is Mutating a Data copy of a Prop object any better than mutating a prop? Why?

In the Vue docs there is a section on one-way data flow: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
Here it explains that you should not mutate a prop. Additionally, it says:
The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it’s best to define a local data property that uses the prop as its initial value:
At the bottom of this section, there is a note that says:
Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child component will affect parent state.
I’m considering the situation where you have a prop that is an object (or an array) and you have defined a local data property that uses the prop as its initial value:
props: {
initialMyObject: {
type: Object,
required: true
}
},
data() {
return {
myObject: this.initialMyObject
}
}
If I mutate the data item myObject, since it is an object the prop itself will end up getting mutated. Is this therefore the same essentially as “mutating a prop” and to be avoided? Would it be preferable in this case to emit an event whenever a change to the object is desired (or to use Vuex)?
Thanks in advance for your help on this.
You can simply clone it though -
data() {
return {
myObject: {...this.initialMyObject}
}
}
To avoid it.
But yeah you just can't reassign a value to a prop as
It's just because Object is kind of reference memory. When you have Array or Object stored in any variable it's a reference variable.
Memory management in such case, The reference variable will points to a memory address in heap so you can add more n more value to address. However you cannot just replace that address with any new value even with the new address.
In my preference, You should prefer Vuex, whenever you want a value to get updated for whole project

How can I pass property getter as a function type to another function

How can I pass property getter to a function that accepts function type?
Here is an example of what I want achieve:
class Test {
val test: String
get() = "lol"
fun testFun(func: ()->String) {
// invoke it here
}
fun callTest() {
testFun(test::get)
// error: Type mismatch: inferred type is
// KFunction1<#ParameterName Int, Char> but () -> String was expected
}
}
Is there a way?
You can reference the getter by writing ::test (or this::test).
When you write test::get, you are actually referencing the get method on String. That method takes an index and returns the character at that index.
If the property was a var and you want a reference to its setter, you can write ::test::set.
For more info on property references, see here: https://kotlinlang.org/docs/reference/reflection.html#bound-function-and-property-references-since-11
As already mentioned, you can use this::test to refer to the getter. Alternatively, if you have kotlin-reflect, you can do this::test.getter.
When you pass the field as a function, it assumes you mean the getter. As a result, if you want the setter, you have two options:
this::test::set
or
this::test.setter
The latter, just like this::test.getter requires kotlin-reflect, or the program will crash (tested locally with Kotlin 1.2.50)
You can, however, get the getter in another way. But I recommend you just stick with this::test because it's shorter.
You can do:
this::something::get
With just something::get it refers to the method inside the String class, which returns a char at an index. For reference, the method declaration:
public override fun get(index: Int): Char
If you don't mind, just use { test } (e.g. testFun { test }). This will exactly translate to your () -> String. The next best alternative is probably ::test (or this::test) as was already mentioned.
The second has probably only minor (negligible?) impact on performance. I did not test it myself, nor did I found any source which tells something regarding it. The reason why I say this, is how the byte code underneath looks like. Just due to this question I asked myself about the difference of the two: Is the property reference (::test) equivalent to a function accessing the property ({ test }) when passed as argument e.g. `() -> String`?
It seems that you are doing something wrong on logical level.
If you are overriding get method of a variable, then you can access it's value through this get method. Thus, why bother with test::get (which is totally different method, by the way, all you are doing is trying to access char from string), when you can just access variable by it's name?

How to call vuex dispatch without remembering names of all actions and send them from dispatch as string?

Doing it like:
this.$store.dispatch({
type: "getUsers",
data
}).then(() => {})
is just annoying. You have to know methods names.
I have something like:
class UserModule extends ListModule<UserState, any, api.UserListItemModel> {
actions = {
// ActionContext requires two arguments State and root state
async getAll(context: ActionContext<UserState, any>, data: Data) {}
}
}
Hot to call that actions.getUsers without that string thingy? Having typescript should have autocomplete in editor so i dont have to remember action names and to dispatch in that matter.
I mean creating some map with names maybe the answer but not sure that i want to create map with 1000 names.
I got resolved with this: https://github.com/istrib/vuex-typescript.
It says:
No string literals or constants for action/mutation/getter names No
action/mutation/getter misuse by providing wrong payload type
Intellisense giving unambiguous hints on what type of payload or getter arguments is expected