Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

hook api? #23

Open
sibelius opened this issue May 8, 2019 · 3 comments
Open

hook api? #23

sibelius opened this issue May 8, 2019 · 3 comments

Comments

@sibelius
Copy link

sibelius commented May 8, 2019

would make sense to transform this in a hook api?

@MichalKalita
Copy link

MichalKalita commented Feb 27, 2020

This works

import * as React from 'react';
import { FormikProps, FormikState } from 'formik';
import debounce from 'lodash.debounce';
import isEqual from 'react-fast-compare';

// Copied from https://usehooks.com/usePrevious/
// License is Unlicensed, https://github.com/gragland/usehooks/blob/master/LICENSE
function usePrevious<T>(value: T): T | undefined {
  // The ref object is a generic container whose current property is mutable ...
  // ... and can hold any value, similar to an instance property on a class
  const ref = React.useRef<T>();

  // Store current value in ref
  React.useEffect(() => {
    ref.current = value;
  }, [value]); // Only re-run if value changes

  // Return previous value (happens before update in useEffect above)
  return ref.current;
}

export function usePersist(
  formik: FormikProps<any>,
  name: string,
  debounceDelay = 300,
  isSessionStorage = false
) {
  const saveForm = React.useMemo(
    () =>
      debounce((data: FormikState<{}>) => {
        if (isSessionStorage) {
          window.sessionStorage.setItem(name, JSON.stringify(data));
        } else {
          window.localStorage.setItem(name, JSON.stringify(data));
        }
      }, debounceDelay),
    [debounceDelay, isSessionStorage, name]
  );

  React.useEffect(() => {
    const maybeState = isSessionStorage
      ? window.sessionStorage.getItem(name)
      : window.localStorage.getItem(name);
    if (maybeState) {
      formik.setValues(JSON.parse(maybeState));
      console.log("set state", maybeState);
    }
  }, []); // deps must be empty, effect will run only on mount

  const previousValues = usePrevious(formik.values);
  React.useEffect(() => {
    if (previousValues && !isEqual(previousValues, formik.values)) {
      saveForm(formik.values);
    }
  }, [formik.values, previousValues, saveForm]);
}

@alonfai
Copy link

alonfai commented Jun 18, 2020

@MichalKalita Its nice solution. However your mount effect hook needs to pass the isSessionStorage and name to the dependency list as this comes from the external caller method. If this changed from session to local storage or vice versa, then the whole context get loaded from the wrapper again.

@suhaotian
Copy link

How about this one https://github.com/suhaotian/use-formik-persist

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants