Search code examples
javascriptrecompose

setState inside componentWillReceiveProps lifecycle Recompose HOC


I'd like to change local state everytime I received a new upcoming props. For this purposes I use a lifecycle HOC from Recompose library. But it's not as simple as I thought. I either set the value forever or the stack overflow occurs when using the callback.

import { connect } from 'react-redux';
import { withState, withProps, lifecycle, compose } from 'recompose';
import { selectors, testDelete, testSubscribe } from 'ducks/entities/tests';
import { Tests } from 'components/tests/all-tests';

export default compose(
  connect(selectors.tests, {
    onTestDelete: testDelete,
    onTestSubscribe: testSubscribe,
  }),
  withState('isDeleteModalOpen', 'setDeleteModalShow', false),
  withState('idToDelete', 'setIdToDelete', 0),
  withProps(
    ({
      tests,
      idToDelete,
      setIdToDelete,
      setDeleteModalShow,
      onTestDelete,
      onTestSubscribe,
    }) => ({
      tests: tests.map((t) =>
        t.merge({
          onDeleteModalShow: () => {
            setDeleteModalShow(true);
            setIdToDelete(t.get('id'));
          },
          onSubscribe: () => onTestSubscribe(t.get('id')),
        }),
      ),
      onDeleteModalHide: () => setDeleteModalShow(false),
      onDelete: () => onTestDelete(idToDelete),
    }),
  ),
  lifecycle({
    componentWillReceiveProps({ setDeleteModalShow }) {
      setDeleteModalShow(false); // Not workding "Maximum update depth exceeded"

      this.setState({
        isDeleteModalOpen: false,
      }); // now working
    },
  }),
)(Tests);


Solution

  • Somewhat old question, but the answer is fairly simple.

    Don't change the state if the value you're setting is already the value that you want it to be. In your code, you could change the lifecycle enhancer to check if the isDeleteModalOpen is already false, like so:

    lifecycle({
      componentWillReceiveProps({ setDeleteModalShow, isDeleteModalOpen }) {
        if (isDeleteModalOpen) setDeleteModalShow(false);
      },
    }),
    

    This way your componentWillReceiveProps function will hit twice and it will do nothing on the second time.

    Be aware that any prop change on this component will set the isDeleteModalOpen value to false.