react-native-mmkv icon indicating copy to clipboard operation
react-native-mmkv copied to clipboard

State Setters from useMMKV hooks shoud support retrieval of previousState

Open fahad86 opened this issue 2 years ago • 9 comments

This is to help with having a clean code with minimal dependancies (and probably fewer re-renders)

For e.g.

const [user, setUser] = useMMKVObject("user");

let newName = "BLAHBLAH";

setUser((prevState) => {
  return {
    ...prevState,
    name: newName
  };
});

fahad86 avatar Aug 21 '23 07:08 fahad86

Good point, but this will be an extra read. What if the user doesn't need the previou state? then it will be an unnecessary DB Read

mrousavy avatar Aug 21 '23 09:08 mrousavy

Is there a way to maybe overload the method (https://www.geeksforgeeks.org/function-overloading-in-javascript/) in such a way that if an arg (prevState) is provided then we do the extra read and perform extra processing and if not then we just maintain the original behaviour?

fahad86 avatar Sep 19 '23 09:09 fahad86

Wait hold on - isn't that already possible?

You can do

const [username, setUsername] = useMMKVString("username")

setUser((prevState) => {
  if (prevState === 'marc')
    return 'fahad86'
  else
    return 'marc'
});

Here's the code for that https://github.com/mrousavy/react-native-mmkv/blob/f564552f262c0a446520fd03f83cd8656acd1917/src/hooks.ts#L68

mrousavy avatar Sep 20 '23 12:09 mrousavy

Aha, it works for everything but not useMMKVObject yet. got it. https://github.com/mrousavy/react-native-mmkv/blob/f564552f262c0a446520fd03f83cd8656acd1917/src/hooks.ts#L178-L202

mrousavy avatar Sep 20 '23 12:09 mrousavy

Aha, it works for everything but not useMMKVObject yet. got it.

https://github.com/mrousavy/react-native-mmkv/blob/f564552f262c0a446520fd03f83cd8656acd1917/src/hooks.ts#L178-L202

I assumed it didn't work for the other setters as well😅.. so what's the plan now?

fahad86 avatar Sep 21 '23 08:09 fahad86

Is there any reason this is not implemented yet? I currently just use my own hook which is pretty straightforward:

function useMMKVObject<T>(key: string) {
    const [json, setJson] = useMMKVString(key);

    const value = React.useMemo<T | undefined>(
        () => (json ? JSON.parse(json) : undefined),
        [json],
    );

    const setValue = React.useCallback(
        (v: (T | undefined) | ((prev: T | undefined) => T | undefined)) => {
            if (v instanceof Function) {
                setJson((currentJson) => {
                    const newValue = v(
                        currentJson ? JSON.parse(currentJson) : undefined,
                    );
                    return JSON.stringify(newValue);
                });
            } else {
                setJson(v ? JSON.stringify(v) : undefined);
            }
        },
        [setJson],
    );

    return [value, setValue];
}

bviebahn avatar Dec 05 '23 13:12 bviebahn

@mrousavy the above solution by @bviebahn looks good right? There is also a related PR: https://github.com/mrousavy/react-native-mmkv/pull/254/files

fahad86 avatar Jan 18 '24 04:01 fahad86

Hey - that PR is outdated, can someone create a new PR with those changes? Then I think we can merge it, however: this is unsafe as there might've been outside modificiations to that data type (e.g. from a notification extension, data loss, or whatever) and the resulting type might not satisfy the type T anymore - so use it at your discretion.

mrousavy avatar Jan 18 '24 08:01 mrousavy

understood. PR created: https://github.com/mrousavy/react-native-mmkv/pull/623 please test to ensure that you don't see any issues in your side

fahad86 avatar Jan 18 '24 09:01 fahad86

Hey - I think this has been fixed in V3 beta.

mrousavy avatar Jul 22 '24 15:07 mrousavy