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鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose fieldRegistry #1853

Open
donaldpipowitch opened this issue Oct 2, 2019 · 2 comments
Open

Expose fieldRegistry #1853

donaldpipowitch opened this issue Oct 2, 2019 · 2 comments

Comments

@donaldpipowitch
Copy link

donaldpipowitch commented Oct 2, 2019

馃殌 Feature request

Current Behavior

Good backends often return the path to a certain field which is invalid (e.g. like in this case). Bad backends sometimes deploy breaking changes without telling the frontend about it and suddenly there is a new mandatory field.

I'd like to handle these cases as well and show validation errors for unknown fields (or create some log somewhere or whatever).

Desired Behavior

Ideally useFormikContext gives me an API which tells me which fields are actually handled in the frontend, so I can figure out from my backend error what I don't handle.

Suggested Solution

The fieldRegistry should be exposed and be treated as read-only, so I can figure out which fields are actually registered.

const fieldRegistry = React.useRef<FieldRegistry>({});

Who does this impact? Who is this for?

Advanced users.

Describe alternatives you've considered

Duplicate the logic behind fieldRegistry and run equivalents to registerField /unregisterField everywhere where I currently already use useField.

@donaldpipowitch
Copy link
Author

donaldpipowitch commented Oct 4, 2019

About Describe alternatives you've considered

Duplicate the logic behind fieldRegistry and run equivalents to registerField /unregisterField everywhere where I currently already use useField.

Here is something for quick copy'n'pasting:

import React, {
  useRef,
  useCallback,
  useEffect,
  createContext,
  FC,
  useContext
} from 'react';

type FieldRegistry = {
  [field: string]: true;
};

type ContextValue = {
  fieldRegistry: FieldRegistry;
  registerField: (name: string) => void;
  unregisterField: (name: string) => void;
};

// pass undefined as any, because we run assertContext at runtime
const FieldRegistryContext = createContext<ContextValue>(undefined as any);

// small util I have in my projects
const assertContext = (context: unknown, name: string) => {
  if (context === undefined)
    throw new Error(
      `Either you or the component you used uses the use${name} hook which needs to be placed inside a ${name}Provider. Please wrap your component inside <${name}Provider></${name}Provider>.`
    );
};

export function useFieldRegistry() {
  const ctx = useContext(FieldRegistryContext);
  assertContext(ctx, 'FieldRegistry');
  return ctx;
}

export function useFieldRegistration(name: string) {
  const { registerField, unregisterField } = useFieldRegistry();

  useEffect(() => {
    registerField(name);
    return () => {
      unregisterField(name);
    };
  }, [name, registerField, unregisterField]);
}

export const FieldRegistryProvider: FC = ({ children }) => {
  const fieldRegistry = useRef<FieldRegistry>({});

  const registerField = useCallback((name: string) => {
    fieldRegistry.current[name] = true;
  }, []);

  const unregisterField = useCallback((name: string) => {
    delete fieldRegistry.current[name];
  }, []);

  return (
    <FieldRegistryContext.Provider
      value={{
        fieldRegistry: fieldRegistry.current,
        registerField,
        unregisterField
      }}
    >
      {children}
    </FieldRegistryContext.Provider>
  );
};

Just wrap your forms inside <FieldRegistryProvider/> and run useFieldRegistration() everywhere where you run useField(). Now you can use const { fieldRegistry } = useFieldRegistry(); in your error handlers.

@stale stale bot added the stale label Dec 3, 2019
@jaredpalmer
Copy link
Owner

Agree.

@jaredpalmer jaredpalmer self-assigned this Jan 7, 2020
@stale stale bot removed the stale label Jan 7, 2020
@stale stale bot added the stale label Mar 7, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants