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

[v2] Hooks #1063

Open
wants to merge 62 commits into
base: master
from

Conversation

@jaredpalmer
Copy link
Owner

jaredpalmer commented Oct 30, 2018

  • Breaking TypeScript change: FormikActions have been renamed to FormikHelpers
  • Formik no longer uses console.error in its warnings, but rather console.warn

Feel free to start making PR's to this branch. This is going to take a minute to figure out as there are a LOT of new paradigms.

#1046 #1005

  • Rebuild <Formik>
  • Field-level registration (need to see if this is actually worth it) (e.g. https://codesandbox.io/s/mz8xzm2w2j)
  • <Field >'s uses handleBlur('path') and handleChange('path') override (#1113)
  • useField's second element is field metadata (#343)
  • Updated TypeScript to 3.2, React 16.7.0-alpha (#1155)
  • Make validation cancellable (#1026, #671)
  • <FastField>
  • Break out useFormik from <Formik>
  • Add canary release channel
  • onReset and handleReset tests
  • async onSubmit (no more setSubmitting(false) needed)
  • Ensure that hooks tests also pass against v1
  • Documentation
    • useField
    • "Creating your own <Fieldset>"
    • Checkboxes and Radio inputs
    • Deprecations
    • <FormikConsumer>
    • useFormikContext
    • useFormik
    • Rewrite examples with hooks
    • Rewrite tutorial with hooks
  • Migration Guide
  • Blog post

@jaredpalmer jaredpalmer changed the base branch from master to 2.0 Oct 30, 2018

@jaredpalmer jaredpalmer changed the base branch from 2.0 to master Oct 30, 2018

@jaredpalmer jaredpalmer requested a review from prichodko Oct 30, 2018

@weyert

This comment has been minimized.

Copy link

weyert commented Oct 31, 2018

Why the rename of FormikContext to FormikCtx?

@tgriesser

This comment has been minimized.

Copy link
Contributor

tgriesser commented Nov 1, 2018

I don't have the time to make this into a formal PR right now but maybe it'll provide a little inspiration. It's a proof-of-concept of Formik working with hooks. Because of the imperative API exposed by formik, the key I found is to mostly use refs internally rather than state, otherwise the values will get stale, e.g. if you set a field and call submitForm in the same event handler. It's just a first pass, so I'm sure there's plenty of room for improvement, but it seems to work alright:

https://gist.github.com/tgriesser/fdd08da075fec80328792319606c76e5

@tgriesser tgriesser referenced this pull request Nov 2, 2018

Open

Hooks Rewrite #1046

jaredpalmer added some commits Nov 2, 2018

@jaredpalmer

This comment has been minimized.

Copy link
Owner Author

jaredpalmer commented Nov 2, 2018

I (think) I'm almost done with useFormik. I made one perf improvement which I think we should push down to v1: avoid toggling isValidating if field-level validation is synchronous.

@jaredpalmer

This comment has been minimized.

Copy link
Owner Author

jaredpalmer commented Nov 2, 2018

@tgriesser hrm. that's definitely a footgun with calling submit form in the same handler. i wonder if there is a way to avoid that aside from ref + force update. refs won't show up in dev tools for example.

jaredpalmer added some commits Nov 2, 2018

@jaredpalmer

This comment has been minimized.

Copy link
Owner Author

jaredpalmer commented Nov 2, 2018

Pretty close here. There is definitely some quirks without the state updater callback

@weyert

This comment has been minimized.

Copy link

weyert commented Nov 5, 2018

How can I extend it with warnings?

@jaredpalmer

This comment has been minimized.

Copy link
Owner Author

jaredpalmer commented Nov 5, 2018

If we decide to allow a stateReducer prop, then yes. However, that debate will come later.

@jaredpalmer jaredpalmer referenced this pull request Nov 6, 2018

Merged

Refactor tests #1087

jaredpalmer added some commits Nov 12, 2018

@weyert

This comment has been minimized.

Copy link

weyert commented Nov 26, 2018

Any way to progress this ticket? :)


export function useFormikContext<Values>() {
return React.useContext<FormikContext<Values>>(PrivateFormikContext);
}

This comment has been minimized.

@crosscompile

crosscompile Jan 18, 2019

Collaborator

I'm not sure if this would just be adding more API without a good use case, but I wonder if it would be worth it to have a hooks only API, something like:

const App = () => {
  const [formik] = useFormik();
  const [form] = useForm(formik);
  const [email] = useField("email", formik);
  const [password] = useField("password", formik);

  return (
    <form {...form}>
      <input {...email} />
      <input {...password} />
    </form>
  );
}

And then FormikContext just puts the values from useFormik on context for that use case.

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

I don’t see this how this api is useful. You will end up having to prop drill.

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

useForm is not a useful hook either IMHO

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

99.999% of our <Form> components have 0 additional props, which to me means it’s a very good abstraction.

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

my goal for useField is to make building your own Fieldset easy AF. Eventually, perhaps even moving/deprecating the current <Field> into its own package a la prop-types

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

it goes without saying that your API would be faster and more perform at because it does not hook into context. however, what is the point of using hooks here aside from useFormik??? just make prop getters and spread?

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

along those lines... this PR already has prop getters. So we technically already support this API by exporting useFormik()

This comment has been minimized.

@crosscompile

crosscompile Jan 18, 2019

Collaborator

Yeah I agree with everything you said, it makes the API less usable.

Feature/hooks tests passing (#1249)
* Fix 'should merge validation errors' test

* Fix 'isValidating is fired validation is run' and others

* Fix 'isSubmitting is fired when submit is attempted' and others

* Fix 'setFieldTouched should NOT run validations when validateOnBlur is false' and others

* Fix 'calls validate during onBlur if present' and others
if (fields.current !== null) {
fields.current[name] = {
validate,
};
}
}

This comment has been minimized.

@crosscompile

crosscompile Jan 18, 2019

Collaborator

I think we might want to wrap all these functions defined in useFormik with useCallback so that we're not creating new functions on every render.

This comment has been minimized.

@crosscompile

crosscompile Jan 18, 2019

Collaborator

But also with ~26 functions that could be a real pain to manage.

I wonder if it's possible to separate the internals of useFormik into logical parts like validation and values. I might experiment with that and report back.

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

Let’s start with useCallback. Let’s discuss how to slice it up. I agree it’s a lot.

This comment has been minimized.

@jaredpalmer

jaredpalmer Jan 18, 2019

Author Owner

Will cut a new release in the meantime

@jaredpalmer

This comment has been minimized.

Copy link
Owner Author

jaredpalmer commented Jan 20, 2019

Just cut a new release.

@sijad

This comment has been minimized.

Copy link

sijad commented Jan 20, 2019

with gamma.1 in react native I get this warning:

useField() / <Field /> must be used underneath a <Formik> component or withFormik() higher order component

I tried render function as render props and children, I'm calling useFormikContext in my component to have access to handleChange and it works.


if (process.env.NODE_ENV !== 'production') {

This comment has been minimized.

@sijad

sijad Jan 20, 2019

it's redundant with tiny-warning

warning(
!(render && children && !isEmptyChildren(children)),
'You should not use <Field render> and <Field children> in the same <Field> component; <Field children> will be ignored'
!formik,

This comment has been minimized.

jaredpalmer and others added some commits Jan 22, 2019

@jaredpalmer jaredpalmer referenced this pull request Feb 11, 2019

Closed

Hooks with Formik #1325

@buzinas

This comment has been minimized.

Copy link

buzinas commented Feb 20, 2019

with gamma.1 in react native I get this warning:

useField() / <Field /> must be used underneath a <Formik> component or withFormik() higher order component

I tried render function as render props and children, I'm calling useFormikContext in my component to have access to handleChange and it works.

Getting the same warning here, but I didn't understand. What was your solution exactly?

@sijad

This comment has been minimized.

Copy link

sijad commented Feb 21, 2019

@buzinas I've send an PR #1348

@max-mykhailenko

This comment has been minimized.

Copy link

max-mykhailenko commented Feb 21, 2019

Does this changes compatible with flow types?

jaredpalmer and others added some commits Feb 21, 2019

Fix warnings (#1348)
* fix warnings

* fix warnings

* Merge branch 'hooks' into pr/1348

* Revert "Merge branch 'hooks-warning-fix' of https://github.com/sijad/formik into pr/1348"

This reverts commit a5434ba, reversing
changes made to 9c85a67.

* Fix activeElement warning

* Revert "Fix activeElement warning"

This reverts commit 3310926.
@otorrillas

This comment has been minimized.

Copy link

otorrillas commented Mar 13, 2019

@jaredpalmer I've been using 2.0.1-alpha (not in prod 🙄) and the experience has been fantastic. Thanks for your efforts here!

Is there something we can help with to release a stable v2? Maybe docs? A migration guide? Thank you!

setFormikState: this.setFormikState,
function getFieldProps(
name: string,
type: string

This comment has been minimized.

@cdoe

cdoe Mar 15, 2019

Couldn't type be optional here?

Suggested change
type: string
type?: string
@buzinas

This comment has been minimized.

Copy link

buzinas commented Mar 15, 2019

How do I create a form with useFormik and useField? From my understanding, useFormik replaces <Formik />, since it receives the same props and return the same stuff that the current render prop passes down to the <form />. The logic seems fine, but I get this error:

TypeError: formik.getFieldProps is not a function

 862 |     process.env.NODE_ENV !== "production" ? warning(formik, 'useField() / <Field /> must be used underneath a <Formik> component or withFormik() higher order component') : void 0;
  863 |   }
  864 | 
> 865 |   return formik.getFieldProps(name, type);
  866 | }

I already tried many different things and I'm out of ideas. The warning says we still need to use <Formik>, so I'm wondering what is useFormik used for?

Thanks in advance!

@cdoe

This comment has been minimized.

Copy link

cdoe commented Mar 15, 2019

@buzinas I'm just recently getting up to speed with the hooks version, so someone please correct me if I'm wrong...

To my understanding, useFormik isn't meant as a drop-in replacement for <Formik />. In fact, useFormik is an altogether new and rather independent thing. It isn't intended to coordinate with useField at all.

I found this doc which may shed some light.

Hope that helps!

@buzinas

This comment has been minimized.

Copy link

buzinas commented Mar 15, 2019

After reading this tweet, I finally could understand what was going on. So now I could solve my problem by using the FormikProvider. Now it's finally pretty easy to create forms in React:

// components/Form/index.js
import React from 'react'
import { useFormik, FormikProvider } from 'formik'
import Fieldset from '../Fieldset'

const Form = ({
  initialValues,
  validationSchema,
  onSubmit,
  children,
  ...props
}) => {
  const formik = useFormik({ initialValues, validationSchema, onSubmit })

  return (
    <FormikProvider value={formik}>
      <form onSubmit={formik.handleSubmit} {...props}>
        <Fieldset disabled={formik.isSubmitting}>{children}</Fieldset>
      </form>
    </FormikProvider>
  )
}

export default Form
// components/InputField/index.js
import React from 'react'
import { useField } from 'formik'

import Field from '../Field'
import Input from '../Input'

const InputField = ({ label, name, onChange, ...props }) => {
  const [field, meta] = useField(name)
  const errorText = meta.touch && meta.error

  return (
    <Field label={label} errorText={errorText}>
      <Input name={name} {...field} {...props} error={!!errorText} />
    </Field>
  )
}

export default InputField

And then to use it:

import React from 'react'

import Form from '../components/Form'
import InputField from '../components/InputField'
import Button from '../components/Button'
import { signInSchema } from '../schemas/authentication'

const SignInForm = () => (
  <Form
    initialValues={{ email: '', password: '' }}
    validationSchema={signInSchema}
    onSubmit={(values, { setSubmitting }) => {
      // fetch('my-api/authenticate') and SUCCESS 🎉 
    }}
  >
    <InputField name="email" label="email" />
    <InputField type="password" name="password" label="password" />
    <Button type="submit" primary>
      Login
    </Button>
  </Form>
)

export default SignInForm
@tz5514

This comment has been minimized.

Copy link

tz5514 commented Mar 26, 2019

@jaredpalmer Thanks for this awesome works!
I already use v2.0.1-alpha.0 for few days, and I found that enableReinitialize feature is missing in Formik.tsx at v2.0, since it has been rewrited by hooks? Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.