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

React Final Form useFormValuesWatch #336

Open
xxleyi opened this issue Oct 3, 2022 · 0 comments
Open

React Final Form useFormValuesWatch #336

xxleyi opened this issue Oct 3, 2022 · 0 comments

Comments

@xxleyi
Copy link
Owner

xxleyi commented Oct 3, 2022

CodeSandbox

import {
  useSyncExternalStore,
  useCallback,
  useEffect,
  useMemo,
  useRef
} from "react";
import { getIn } from "final-form";
import { useForm } from "react-final-form";

export const useFormValuesWatch = (options) => {
  const { watch, names } = options;
  const watchRef = useRef(watch);
  watchRef.current = watch;

  const namesRef = useRef(names);
  const steadyStateRef = useRef();

  const form = useForm();
  const getSnapshot = useMemo(() => {
    const currentValues = form.getState().values;
    steadyStateRef.current = names.map((name) => getIn(currentValues, name));
    namesRef.current = names;

    return () => {
      const currentValues = form.getState().values;
      const newValues = names.map((name) => getIn(currentValues, name));
      const hasNew = steadyStateRef.current.some(
        (old, idx) => old !== newValues[idx]
      );
      if (hasNew) {
        steadyStateRef.current = newValues;
      }
      return steadyStateRef.current;
    };
    // need Tuple !!!!!!
  }, [...names, form]);

  const latest = useSyncExternalStore(
    useCallback((callback) => form.subscribe(callback, { values: true }), [
      form
    ]),
    getSnapshot
  );

  const result = useMemo(
    () => ({
      values: latest,
      form,
      names: namesRef.current
    }),
    [latest, form]
  );

  useEffect(() => {
    if (!watchRef.current) return;
    watchRef.current(result);
  }, [result]);

  return result;
};

再配合 FormSpy + React.memo 可以在默认的 form 全量 rerender 情况下,实现局部的表单状态订阅,并且可以精细到 form values 的具体字段。具体可见 https://codesandbox.io/p/sandbox/fine-form-values-watch-zfhy5h?file=%2Findex.js

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

1 participant