Formik: FormikEffect throws errors after upgrade to Formik@1

Created on 16 Jul 2018  路  11Comments  路  Source: formium/formik

Current Behavior

throws an error:

Cannot read property 'values' of undefined
TypeError: Cannot read property 'values' of undefined
    at Effect.webpackJsonp../node_modules/formik-effect/dist/formik-effect.es6.js.Effect.componentWillReceiveProps (node_modules/formik-effect/dist/formik-effect.es6.js:38:0)
    at callComponentWillReceiveProps (node_modules/react-dom/cjs/react-dom.development.js:11527:0)
    at updateClassInstance (node_modules/react-dom/cjs/react-dom.development.js:11719:0)
    at updateClassComponent (node_modules/react-dom/cjs/react-dom.development.js:13153:0)
    at beginWork (node_modules/react-dom/cjs/react-dom.development.js:13824:0)
    at performUnitOfWork (node_modules/react-dom/cjs/react-dom.development.js:15863:0)
    at workLoop (node_modules/react-dom/cjs/react-dom.development.js:15902:0)
    at renderRoot (node_modules/react-dom/cjs/react-dom.development.js:15942:0)
    at performWorkOnRoot (node_modules/react-dom/cjs/react-dom.development.js:16560:0)
    at performWork (node_modules/react-dom/cjs/react-dom.development.js:16482:0)

Expected behavior

Not to throw an error :)


  • Formik Version: 1.0.1
  • React Version: 16.4.1
  • TypeScript Version: n/a
  • Browser and Version: any browser
  • OS: MacOS 10.13
  • Node Version: 10.6.0
  • Package Manager and Version: npm 6.2.0
stale

Most helpful comment

I'm using the following (derived mostly from @FabianSellmann above):

import * as React from 'react';
import { connect } from 'formik';

class FormikEffect extends React.Component {
  componentDidUpdate(prevProps) {
    if (prevProps.formik !== this.props.formik) {
      this.props.onChange(this.props.formik, prevProps.formik);
    }
  }

  render() {
    return null;
  }
}

export default connect(FormikEffect);

Calling it as:

<FormikEffect onChange={(current, prev) => {
  if (current.values.someKey !== prev.values.someKey) {
    console.info('someKey changed to', current.values.someKey);
  }
}} />

All 11 comments

Codesandbox link pls

Formik is using new Provider/Consumer from react 16.3, while formik-effect library still relies on old context api.

I am using withFormik hoc, so I was able to do something like this with lodash and componentWillReceiveProps:

    componentWillReceiveProps(nextProps) {
        if (!isEmpty(nextProps.values) && !isEqual(this.props, nextProps)) {
            // values have changed
        }
    }

formik-effect does almost the same thing internally:
https://github.com/jaredpalmer/formik-effect/blob/master/src/formik-effect.tsx

@jaredpalmer any work around on this? either fixing formik-effect or something else..

import * as React from "react";
import { FormikProps, FormikState, connect } from "formik";

export interface IEffectProps<TValues = {}> {
    onChange(
        currentState: FormikState<TValues>,
        prevState: FormikState<TValues>
    ): void;
    formik: FormikProps<TValues>;
}

const Effect = class FormikEffect<TValues = {}> extends React.Component<IEffectProps<TValues>, {}> {

    componentDidUpdate(prevProps: IEffectProps<TValues>) {
        const { values, touched, errors, isSubmitting, isValidating } = this.props.formik;
        const {
            values: prevValues,
            touched: prevTouched,
            errors: prevErrors,
            isSubmitting: prevIsSubmitting,
            isValidating: prevIsValidating
        } = prevProps.formik;
        if (prevProps.formik !== this.props.formik) {
            this.props.onChange({
                    values,
                    touched,
                    errors,
                    isSubmitting,
                    isValidating
                } as FormikState<TValues>,
                {
                    values: prevValues,
                    touched: prevTouched,
                    errors: prevErrors,
                    isSubmitting: prevIsSubmitting,
                    isValidating: prevIsValidating
                } as FormikState<TValues>
            );
        }
    }

    render() {
        return null;
    }
}

export default connect(Effect);

Uses formik prop induced by connect instead directly accessing context. Also note that it uses the componentDidUpdate lifecycle function instead of componentWillReceiveProps.

Hola! So here's the deal, between open source and my day job and life and what not, I have a lot to manage, so I use a GitHub bot to automate a few things here and there. This particular GitHub bot is going to mark this as stale because it has not had recent activity for a while. It will be closed if no further activity occurs in a few days. Do not take this personally--seriously--this is a completely automated action. If this is a mistake, just make a comment, DM me, send a carrier pidgeon, or a smoke signal.

ProBot automatically closed this due to inactivity. Holler if this is a mistake, and we'll re-open it.

I believe this hasn't been fixed, it just happened to me with the last versions of Formik (1.3.2) & FormikEffect (1.2.0).

I'm using the following (derived mostly from @FabianSellmann above):

import * as React from 'react';
import { connect } from 'formik';

class FormikEffect extends React.Component {
  componentDidUpdate(prevProps) {
    if (prevProps.formik !== this.props.formik) {
      this.props.onChange(this.props.formik, prevProps.formik);
    }
  }

  render() {
    return null;
  }
}

export default connect(FormikEffect);

Calling it as:

<FormikEffect onChange={(current, prev) => {
  if (current.values.someKey !== prev.values.someKey) {
    console.info('someKey changed to', current.values.someKey);
  }
}} />

I'm using the following (derived mostly from @FabianSellmann above):

import * as React from 'react';
import { connect } from 'formik';

class FormikEffect extends React.Component {
  componentDidUpdate(prevProps) {
    if (prevProps.formik !== this.props.formik) {
      this.props.onChange(this.props.formik, prevProps.formik);
    }
  }

  render() {
    return null;
  }
}

export default connect(FormikEffect);

Calling it as:

<FormikEffect onChange={(current, prev) => {
  if (current.values.someKey !== prev.values.someKey) {
    console.info('someKey changed to', current.values.someKey);
  }
}} />

This helped me thanks

@dlerman2's above example produces an error in React 16.3.0:

Warning: Cannot update a component from inside the function body of a different component.

This is from a change in React stating, "A React component should not cause side effects in other components during rendering." The workaround is to call the handler in a useEffect hook.

This solution works for me:

import { connect } from 'formik';
import { useEffect, useState, useRef } from 'react';

function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

function FormikEffect({ onChange, formik: { values } }) {
  const [firstRender, setFirstRender] = useState(true);
  const previousValues = usePrevious(values);

  useEffect(() => {
    if (firstRender) {
      setFirstRender(false);
    } else {
      onChange(previousValues, values);
    }
  }, [onChange, values]);

  return null;
}

export default connect(FormikEffect);
Was this page helpful?
0 / 5 - 0 ratings

Related issues

emartini picture emartini  路  3Comments

jordantrainor picture jordantrainor  路  3Comments

dearcodes picture dearcodes  路  3Comments

ancashoria picture ancashoria  路  3Comments

sibelius picture sibelius  路  3Comments