use-persisted-state icon indicating copy to clipboard operation
use-persisted-state copied to clipboard

return memoized object if it equals current value

Open FezVrasta opened this issue 5 years ago • 5 comments
trafficstars

Right now this hook can produce unexpected hooks because it will return a different object even if its value is identical to the previous one.

Considered that we are working with JSON data, it would be safe to do a value equality check any time we parse the new value, and if it matches the previous one, we should return the previous one to preserve its identity.

FezVrasta avatar May 15 '20 14:05 FezVrasta

As workaround, for now I'm using this wrapper:

import { useRef } from 'react';
import { equals } from 'ramda';
import _createPersistedState from 'use-persisted-state';

const useMemoizedObject = (obj) => {
  const mem = useRef();
  if (equals(mem.current, obj)) {
    return mem.current;
  } else {
    mem.current = obj;
    return obj;
  }
};

const createPersistedState = (key) => {
  const usePersistedState = _createPersistedState(key);

  return (initialValue) => {
    const [_value, setValue] = usePersistedState(initialValue);
    const value = useMemoizedObject(_value);

    return [value, setValue];
  };
};

export default createPersistedState;

FezVrasta avatar May 16 '20 14:05 FezVrasta

As workaround, for now I'm using this wrapper:

import { useRef } from 'react';
import { equals } from 'ramda';
import _createPersistedState from 'use-persisted-state';

const useMemoizedObject = (obj) => {
  const mem = useRef();
  if (equals(mem.current, obj)) {
    return mem.current;
  } else {
    mem.current = obj;
    return obj;
  }
};

const createPersistedState = (key) => {
  const usePersistedState = _createPersistedState(key);

  return (initialValue) => {
    const [_value, setValue] = usePersistedState(initialValue);
    const value = useMemoizedObject(_value);

    return [value, setValue];
  };
};

export default createPersistedState;

Could you do something like the following for the same result?

import createPersistedState from 'use-persisted-state'
import { useMemo } from 'react'

const useLocalStorage = (key: string, initialValue: any) => {
  const usePersistedState = createPersistedState(key)

  const [_value, setValue] = usePersistedState(initialValue)
  const value = useMemo(() => _value, [_value])

  return [value, setValue]
}

export default useLocalStorage


natac13 avatar Jul 07 '20 17:07 natac13

No, useMemo doesn't perform a deep comparison

FezVrasta avatar Jul 07 '20 17:07 FezVrasta

I did not know that. Thanks!

natac13 avatar Jul 07 '20 17:07 natac13

I am working on this (https://github.com/dennismorello/use-persisted-state/tree/feature/deep-comparison). I will open a PR when I'm done 👍🏻

morellodev avatar Nov 09 '20 17:11 morellodev