formik-effect icon indicating copy to clipboard operation
formik-effect copied to clipboard

Cannot read property 'values' of undefined

Open pgrekovich opened this issue 6 years ago • 18 comments

One of these days there was this error. Any idea what might be the problem?

screenshot_3

pgrekovich avatar May 17 '18 00:05 pgrekovich

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?

latviancoder avatar Jun 08 '18 17:06 latviancoder

@jaredpalmer any update or plans on this?

maticrivo avatar Jul 29 '18 13:07 maticrivo

@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 avatar Jul 29 '18 15:07 pgrekovich

@pgrekovich componentDidUpdate will only work if I use formik as an HOC with withFormik but i use formik with a render prop

maticrivo avatar Jul 29 '18 19:07 maticrivo

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);

NamPNQ avatar Aug 03 '18 09:08 NamPNQ

@jaredpalmer any update on this issue?

sreeram-muddu avatar Sep 10 '18 17:09 sreeram-muddu

Hey .. I've got the same issue.

luke-dare avatar Oct 05 '18 11:10 luke-dare

@jaredpalmer ping, same issue here

h0jeZvgoxFepBQ2C avatar Nov 14 '18 13:11 h0jeZvgoxFepBQ2C

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 avatar Dec 13 '18 03:12 brandonhall

@brandonhall Thanks for sharing! Using your example gives me IProps is not defined. Did you define it somewhere else?

Ridder90 avatar Mar 04 '19 15:03 Ridder90

@Ridder90 No, it's defined at the top of the file as a TypeScript interface.

brandonhall avatar Mar 04 '19 16:03 brandonhall

Hmmm strange...running it with export default connect(FormikEffects); works perfectly though.

Ridder90 avatar Mar 04 '19 16:03 Ridder90

Any eta when this will be fixed? I'm getting the same issue

sebastianpatten avatar Apr 14 '19 19:04 sebastianpatten

Same here; would love a fix for this

BrianBusby avatar Apr 18 '19 16:04 BrianBusby

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 :)

aronkof avatar May 01 '19 19:05 aronkof

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 avatar Jul 22 '19 16:07 leechingching

@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

NamPNQ avatar Jul 23 '19 02:07 NamPNQ

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);

jariz avatar Oct 18 '19 13:10 jariz