formik-effect
formik-effect copied to clipboard
Cannot read property 'values' of undefined
One of these days there was this error. Any idea what might be the problem?
formik is using new Provider/Consumer from react 16.3, while this library still relies on old context api.
@jaredpalmer are you planning on updating this?
@jaredpalmer any update or plans on this?
@maticrivo I had spent time to understand it, and in real life, you don't need it! Try to use componentDidUpdate if you need to update something after the form has updated.
@pgrekovich componentDidUpdate
will only work if I use formik as an HOC with withFormik
but i use formik with a render
prop
Just use connect api Here is my solution
// @flow
import React from 'react';
import { connect } from 'formik';
type Props = {
onChange: Function,
formik: Object,
};
class Effect extends React.Component<Props> {
componentWillReceiveProps(nextProps) {
const { values, touched, errors, isSubmitting } = this.props.formik;
const {
values: nextValues,
touched: nextTouched,
errors: nextErrors,
isSubmitting: nextIsSubmitting,
} = nextProps.formik;
if (nextProps.formik !== this.props.formik) {
this.props.onChange(
{
values,
touched,
errors,
isSubmitting,
},
{
values: nextValues,
touched: nextTouched,
errors: nextErrors,
isSubmitting: nextIsSubmitting,
},
);
}
}
// eslint-disable-next-line
render() {
return null;
}
}
export default connect(Effect);
@jaredpalmer any update on this issue?
Hey .. I've got the same issue.
@jaredpalmer ping, same issue here
My solution was very similar to @NamPNQ and works great for us:
import { Component } from 'react';
import { debounce, isEqual } from 'lodash';
import { connect, FormikValues, FormikProps } from 'formik';
interface IProps {
onChange: (values: FormikValues) => void;
}
interface IPropsEnhanced extends IProps {
formik: FormikProps<FormikValues>;
}
const SAVE_DELAY = 1000;
class FormikEffects extends Component<IPropsEnhanced> {
onChange = debounce(this.props.onChange, SAVE_DELAY);
componentDidUpdate(prevProps: IPropsEnhanced) {
const { formik } = this.props;
const { isValid } = formik;
const hasChanged = !isEqual(prevProps.formik.values, formik.values);
const shouldCallback = isValid && hasChanged;
if (shouldCallback) {
this.onChange(formik.values);
}
}
render() {
return null as null;
}
}
export default connect<IProps>(FormikEffects);
@brandonhall Thanks for sharing! Using your example gives me IProps is not defined
. Did you define it somewhere else?
@Ridder90 No, it's defined at the top of the file as a TypeScript interface.
Hmmm strange...running it with export default connect(FormikEffects);
works perfectly though.
Any eta when this will be fixed? I'm getting the same issue
Same here; would love a fix for this
Just use connect api Here is my solution
// @flow import React from 'react'; import { connect } from 'formik'; type Props = { onChange: Function, formik: Object, }; class Effect extends React.Component<Props> { componentWillReceiveProps(nextProps) { const { values, touched, errors, isSubmitting } = this.props.formik; const { values: nextValues, touched: nextTouched, errors: nextErrors, isSubmitting: nextIsSubmitting, } = nextProps.formik; if (nextProps.formik !== this.props.formik) { this.props.onChange( { values, touched, errors, isSubmitting, }, { values: nextValues, touched: nextTouched, errors: nextErrors, isSubmitting: nextIsSubmitting, }, ); } } // eslint-disable-next-line render() { return null; } } export default connect(Effect);
Thanks, it works as expected :)
My solution was very similar to @NamPNQ and works great for us:
import { Component } from 'react'; import { debounce, isEqual } from 'lodash'; import { connect, FormikValues, FormikProps } from 'formik'; interface IProps { onChange: (values: FormikValues) => void; } interface IPropsEnhanced extends IProps { formik: FormikProps<FormikValues>; } const SAVE_DELAY = 1000; class FormikEffects extends Component<IPropsEnhanced> { onChange = debounce(this.props.onChange, SAVE_DELAY); componentDidUpdate(prevProps: IPropsEnhanced) { const { formik } = this.props; const { isValid } = formik; const hasChanged = !isEqual(prevProps.formik.values, formik.values); const shouldCallback = isValid && hasChanged; if (shouldCallback) { this.onChange(formik.values); } } render() { return null as null; } } export default connect<IProps>(FormikEffects);
It works as expected, but the console shows the warming below
react-dom.development.js:506 Warning: A component is changing an uncontrolled input of type undefined to be controlled. Input elements should not switch from uncontrolled to controlled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component. More info: https://fb.me/react-controlled-components
Do you have any ideas how to solve it ?
@leechingching it's not related with this issue, you can check the guide in https://fb.me/react-controlled-components, may be your component dont set value back in input
Here's my version recreating formik-effect with hooks in 11 lines.
See here for TS version.
import { connect } from 'formik';
import { useEffect, useRef } from 'react';
const Effect = ({ formik, onChange }) => {
const ref = useRef(null);
useEffect(() => {
onChange(formik, ref.current);
ref.current = formik;
}, [formik]);
return null;
};
export default connect(Effect);