Since switching <Formik /> to a function component if you try to attach a ref to it as such:
<Formik ref={myRef} />
you will get the following error:
Warning: Function components cannot be given refs. Attempts to access this ref will fail. Did you mean to use React.forwardRef()?
The desired behaviour is for there to be no error and the ref to provide a set of APIs to programmatically interact with <Formik />.
To enable the functionality it seems that the hook useImperativeHandle will be needed to wrap <Formik/> and expose the available methods.
export const Formik = forwardRef((props, ref) => {
const formikRef = useRef()
useImperativeHandle(ref, () => ({
submitForm: () => handleSumbit()
})
return (
<FormikProvider ref={formikRef} value={formikbag}>
{...}
</FormikProvider>
)
})
An example per the docs
This is for anyone who needs to implement any programmatic functionality on
Use the prior version where
I was trying to implement the debounced autosave that was handled by the parent component, without the need for a specific component that is a child of
I guess this applies to withFormik aswell?
I have two forms similar to:
https://codesandbox.io/s/formik-multiple-form-in-one-submission-kbf1w?fontsize=14
I would like to make a reset button that runs formik.resetForm() on both forms.
I can get a reference to the withFormik react node, but not child which is the actual Formik react node (which I'm guessing provides the formikBag API I need).
Ideas?
Have you made any progress with this? I'm facing a similar problem.
I managed to get this to work by passing in the ref as a propery.
const formikFormRef = useRef(null); //in parent
<FormikForm formikFormRef={formikFormRef} ></FormikForm> // in parent
Then inside the form
const FormikForm = (withFormik({ enableReinitialize: true})((props, values) => {
useImperativeHandle(props.formikFormRef, () => ({
autoSave: () => {
console.log('xxx');
}
}));
Now I can call this from the parent with:
useEffect(() => {
setInterval(() => {
formikFormRef.current.autoSave()
}, 3000);
});
});
Any updates?
Any updates on this, I can't upgrade to v2 because I have to reset some forms in my app using the reference from outside the form itself
PR's welcome.
I would like to be able to implement this, but I don't know how to fix the interface FormikConfig to handle the type of the ref using forwardRef :disappointed:
Do we really need this? While you can't do <Formik ref={myRef} /> passing it as <Formik myRef={myRef} /> works. Then you can subscribe to it using useImperativeHandle(props.myRef, () => {}) from within the form and call it from outside as myRef.current.fooBar(). See my previous post for full example.
Hey guys. Do you have any thoughts on @johnrom suggestion?
Please, check this PR: https://github.com/jaredpalmer/formik/pull/1972
How is this for a work-around? Our code is still on v1 and it works but I haven't tested with v2.
render() {
const { children, ...props } = this.props;
return (
<Formik {...props}>
{formikProps => {
this.formikProps = formikProps;
return this.renderChildren(formikProps);
}}
</Formik>
);
}
Here is a workaround that works for me in v2.
useImperativeHandle // FormikWithRef.tsx
import React, {forwardRef, useImperativeHandle} from 'react';
import {Formik, FormikProps, FormikConfig} from 'formik';
function FormikWithRef(props: FormikConfig<any>, ref) {
let _formikProps: FormikProps<any>;
useImperativeHandle(ref, () => (_formikProps));
return (
<Formik {...props}>
{(formikProps) => {
_formikProps = formikProps;
if (typeof props.children === 'function') {
return props.children(formikProps);
}
return props.children;
}}
</Formik>
);
}
export default forwardRef(FormikWithRef)
Then I use the new component; FormikWithRef instead of Formik;
// LoginPage.tsx
import {useRef} from 'react';
import {FormikProps} from 'formik';
export default function LoginPage() {
const myFormRef = useRef<FormikProps<any>>(null);
return <FormikWithRef ref={myFormRef}>
{({
values,
errors,
touched,
handleChange,
handleBlur,
handleSubmit,
isSubmitting,
}) => (
<form onSubmit={handleSubmit}>
// ...
</form>
)}
</FormikWithRef>
}
What's the status of this? I see this was closed, and I can see useImperativeHandle in the codebase in 2.1.2, but I can't pass a ref into the
I get the TS error: Property 'ref' does not exist on type 'IntrinsicAttributes & FormikConfig<...>
You can get a ref to formikBag via innerRef prop.
const bagRef = useRef();
<Formik innerRef={bagRef} />
Note: this isn't a reference to the Formik component, but to the "bag" of formik tools. like handleSubmit et all. I think using ref prop was avoided so that in the future if there's a reason to add a real ref, we can.
To me this looks like an undocumented breaking change that should be included in "Migrating to v2" of docs.
It is also poorly typed, the innerRef is of type (instance: any) => void
@teotn it is quite poorly typed 馃憥 . We're discussing a real implementation here: #2208
@johnrom What would be the classes equivalent?
I'm trying with useRef but it seems that it is intended only for function hooks, and createRef with ref doesn't work either.
For Formik slug being "without tears", I already have dropped a lot :(
@diosney useRef is specific to functional "React hooks". functional components are generally considered preferable to classes in many scenarios except some very complex use cases that functional components cannot be used for. however, for backwards compatibility the class-based ref method is
class MyClass = {
public constructor(props) {
super(props);
this.myRef = React.createRef();
}
render() {
return (
<Formik innerRef={this.myRef} />
);
}
}
Note, besides using innerRef instead of ref, this has nothing to do with Formik, and those are just plain ol' React tears.
@johnrom Thanks for your answer and sorry for my grunt, but I have several rounds on this already and tested lot of things without making it working as it should, I'm really just about pulling my off my hair.
I already tried your solution with createRef, even repeated using constructor since I do not do it like that (using typescript sugar classes) but it keeping outputing:
{"current": null}
and any call to this.myRef.errors or this.myRef.current.errors or any other Formik "bag" property gives an error.
The only way I could get some partial success was by something like:
{(formikProps) => {
self.formSubmit = formikProps.handleSubmit;
self.formIsValid = formikProps.isValid;
self.formErrors = formikProps.errors;
....
but for some wicked reason it only works if I made some change in the code while developing and having Hot Reload enabled.
Have any other suggestions?
Really don't know why it is not working, I updated Formik to 2.1.4 from 2.1.1 and all remains the same.
I'm trying to use those values on a Button below and outside the Formik component.
@diosney if you open a new issue someone may be able to help you there. during issue creation, you should try and reproduce your issue in a CodeSandbox (link to the sandbox starter is in the new issue creation template). You might figure out where the issue is during reproduction (happens a lot!), or if you are able to reproduce we'll be able to look immediately and see where the problem is.
@johnrom OK, I understand, thanks for your time.
Most helpful comment
You can get a ref to
formikBagviainnerRefprop.Note: this isn't a reference to the Formik component, but to the "bag" of formik tools. like
handleSubmitet all. I think usingrefprop was avoided so that in the future if there's a reason to add a real ref, we can.