Code Update - useMMKVObject doesn't force undefined.
I think this interface change for useMMKVObject is better; the developer can define if undefined is allowed or not.
export function useMMKVObject<T>(
key: string,
initialValue: T,
instance?: MMKV,
): [
value: T,
setValue: (
value: T | ((prevValue: T) => T | void)
) => void,
] {
const [json, setJson] = useMMKVString(key, instance);
const value = useMemo(() => {
if (json == null) return initialValue;
return JSON.parse(json) as T;
}, [json]);
const setValue = useCallback(
(v: (T) | ((prev: T) => T | void)) => {
if (v instanceof Function) {
setJson((currentJson) => {
const currentValue =
currentJson != null ? (JSON.parse(currentJson) as T) : initialValue;
const newValue = v(currentValue);
// Store the Object as a serialized Value or clear the value
return newValue != null ? JSON.stringify(newValue) : undefined;
});
} else {
// Store the Object as a serialized Value or clear the value
const newValue = v != null ? JSON.stringify(v) : undefined;
setJson(newValue);
}
},
[setJson]
);
return [value, setValue];
}
I haven't tested it yet but the changes are quite small to implement.
Guten Tag, Hans here! 🍻
Danke for your suggestion, but it seems like you are proposing a potential change without testing it yet. Please try implementing your change and testing it for any issues. Additionally, if you have any specific problems or bugs with useMMKVObject, feel free to describe them in detail so we can help you resolve them better.
Also, don’t forget to check out our sponsorship options if you want to help support ze maintenance of this project!
Looking forward to your updates!
Note: If you think I made a mistake, please ping
@mrousavyto take a look.
I can make a pull request, but it'd be good to know if this change is wanted.
what exactly did you change?
The value is just 'T' instead of 'T | undefined' for the interface. And the initial value param.
ah this makes sense!
i wonder if a binary serialization is better looking at this now
I just found out that the setter function should allow void in order to get the same instance of the value (if by reference).
An example:
const [obj, setObj] = useMMKVObject(...)
const update = (item) => {
setObj((old) => {
if (item.id !== old.id) {
return
}
return item
})
}
test (psuedo code but something like this)
it('returns the same instance if the id is different', () => {
const initialObj = { id: '123' }
const result = renderHook(...)
result.current.update({ id: '456' })
expect(result.current.obj).toBe(initialObj)
})
But this change doesn't mess anything up. I'll update the original post.
EDIT:
Although, I'm not sure why this is working. But there should be a test to get the same instance after calling the setter.
Did you want me to make changes and create a pull request?
why not just return the same object? That's reference equality no?
setObj((old) => {
if (item.id !== old.id) {
return old
}
return item
})
why not just return the same object? That's reference equality no?
That's what I originally did but it broke my test. I haven't dug any further.
EDIT:
I don't know why my test was passing. Maybe a race condition?... but at some point, I updated my tests and it failed correctly.
Now I'm returning the "old" value but it's not returning as the same reference. Again, I'm not sure why, because it looks like the useMemo should recognize the same json and return the same instance.
When I have the time, I'll create a PR for review so you can check it out.
PRs welcome