Skip to content

Chore: Refactor to the new Context.unstable_read() API #814

Closed
@jaredpalmer

Description

@jaredpalmer

Current Behavior

Currently, we use connect() to wire up components to Formik's context. This creates an extra node for <Field>, <Form>, and <FastField> because connect() is simply a wrapper around the <FormikContext.Consumer> render prop.

Desired Behavior

Remove connect() usage internally and instead use Andrew's forthcoming Context.unstable_read() (facebook/react#13139) which allows reading context within any render-phase function.

Suggested Solution

Pretty straight forward. We rename <XXXXImpl> to just <XXXX> and get rid of connect() usage internally (i.e. remove my poorly typed HoC TypeScript nonsense at the bottom of the files). We will still need interface FormikContext because I expect that the TS type signature for .unstable_read() will take a TS generic.

// FormikContext.js
export const FormikContext = React.createContext('');
// Field.js
import React from 'react'
import { FormikContext } from './FormikContext';

export const Field = ({ component = 'input', name, ...rest }) => {
  // Yes. This is real.
  const { handleChange, handleBlur, values } = FormikContext.unstable_read();
  
  // handwaiving the rest...
  return React.createElement(component, {
    onChange: handleChange,
    onBlur: handleBlur,
    value: values[name] || '',
    name,
    ...rest,
  });
};

Who does this impact? Who is this for?

We will still export connect() so no breaking changes there. However, enzyme tests may break AGAIN because of these changes because we are going to be removing a node from the tree for each component (no more FieldImpl, just Field). 🤣 🤣. We can now go back to shallow rendering instead of mount though!

Additional context / Discussion

  • We may end up moving <Field> to an SFC and moving all the class functions down into render. I need to ask Dan/Andrew about pros / cons.
  • Decide if we should deprecate connect() with a warning, since this API will be the future.
  • Would be great to expose new "context getters" ™️ so that people don't even need <Field> to create their own custom components? I'm not sure where these would get defined? Maybe in getDerivedStateFromProps in Formik? idk. Need to ask.

Metadata

Metadata

Assignees

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions