React - update state hook fails on netlify - works on local

Hello Netlify community,
This is my first post on the forums. I a boot camp student, 3/4 through my course, and loving it. I aspire to be as self-reliant as I possibly can, but am at a loss to what is happening on my team’s netlify deployed React website — hosted here: https://the-door-nyc.netlify.app/

I should be clear – I am posting this at Netlify Community not because it’s a problem with Netlify per se, but because it runs fine on localhost. Something about Netlify must breaking on our React architecture. And no, it’s not a react-router redirect issue. Our change of screen is caused by conditional rendering driven by component state.

EXPECTED FUNCTIONALITY: at the sign-up URL (https://the-door-nyc.netlify.app/sign-up) a volunteer can create a new record by entering strings for first four fields (must be valid email format, other fields are free) + checking at least 1 box in either of the two checkbox groups. Submit button is active on these conditions.

onSubmit – XHR hits the back-end OK. Also onSubmit, the useState hook setFormStatus('submitted') will fire. This tells the parent component what control flow it should take, to render a confirmation screen instead of a form.

At the confirmation screen, user can click Update button to return to previous form, pre-populated with their info. The submit button is as before, with slight differences (button value is “update” rather than “submit”; XHR is for PUT instead of POST.) Clicking it fires setFormStatus(‘submitted’) and we SHOULD go back to confirmation screen exactly as before.

THE BREAK: on localhost, the above works as expected. On netlify, setFormStatus alters state as expected the first time (record creation). It does NOT alter state on the second time (record update). All XHRs continue functioning normally.


TLDR: the useState hook “setFormStatus” is triggered by an onSubmit button in a child React component to alter state in its parent.

It runs fine in localhost, changing parent state…
…from to ‘submitted’;
…from ‘submitted’ to ‘edit’
…from ‘edit’ to ‘submitted.’

On Netlify, state fails to change at third case (‘edit’ to ‘submitted’). This lack of change is visible in React Dev Tools.

RELEVANT CODE:
VolunteerForm.jsx - the child component form

function VolunteerForm({
  formStatus,
  setFormStatus,
  volunteerId,
  setVolunteerId,
 
}) {
  const [volunteer, setVolunteer] = useState({
    firstName: '',
    lastName: '',
    phone: '',
    email: '',
    programs: [],
    roles: [],
  })
  const [serverErrors, setServerErrors] = useState({})

  const history = useHistory()

  useEffect(() => {
    if (formStatus === 'edit') {
      async function fetchVolunteer() {
        const volunteer = await getVolunteer(volunteerId)
        setVolunteer(volunteer)
      }
      fetchVolunteer()
    }
  }, [volunteerId])

  return (
    <>
      ...

            <Formik
              initialValues={volunteer}
              enableReinitialize
              // isValid
              validate={(values) => {
                const errors = {}
                if (!values.firstName) errors.firstName = 'Required'
                if (!values.lastName) errors.lastName = 'Required'
                if (!values.phone) errors.phone = 'Required'
                if (!values.email) {
                  errors.email = 'Required'
                } else if (
                  !/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.test(
                    values.email
                  )
                ) {
                  errors.email = 'Please enter a valid e-mail address'
                }
                if (values.programs.length === 0)
                  errors.programs = 'Please select a program choice.'
                if (values.roles.length === 0)
                  errors.roles = 'Please select a roles choice.'
                return errors
              }}
              **onSubmit**={async (value) => {
                let response
                if (formStatus === 'edit') {
                  response = await updateVolunteer(volunteerId, value)
                } else {
                  response = await createVolunteer(value)
                  await setVolunteerId(response.data._id)
                }
                // if Status is NOT OK
                if (!(response.status >= 200 && response.status <= 300)) {
                  return setServerErrors(response.data)
                }
                // implied "else" ...
                **setFormStatus('submitted')**
              }}>

              {(props) => (
                <form onSubmit={props.handleSubmit}>
                  
                   ...

                  <div className='button-area'>
                    <button
                      className={`form submit-button ${
                        props.isValid && (props.dirty || formStatus === 'edit')
                          ? 'active'
                          : null
                      }`}
                      type='submit'>
                      <span className='button-text'>
                        {formStatus === 'edit' ? 'Update' : 'Submit'}
                      </span>
                    </button>

                    {formStatus === 'edit' && (
                      <button
                        className={'form delete-button active'}
                        onClick={() => {
                          deleteVolunteer(volunteerId)
                          history.push('/')
                        }}>
                        <span className='button-text'>Nevermind</span>
                      </button>
                    )}
                  </div>
                </form>
              )}
            </Formik>
       ...
    </>
  )
}

FormScreen.jsx - the parent, a state-driven screen "router"

```function FormScreen() {
  const [formStatus, setFormStatus] = useState('')
  const [volunteerId, setVolunteerId] = useState('')
  const [modalOpen, setModalOpen] = useState(false)

  if (!formStatus) {
    return (
      <div className='form-screen'>
        <VolunteerForm
          setFormStatus={setFormStatus}
          setVolunteerId={setVolunteerId}
        />
      </div>
    )
  } else if (formStatus === 'submitted') {
    return (
      <div className='form-screen'>
        <Modal show={modalOpen} />
        <Confirmation
          volunteerId={volunteerId}
          setFormStatus={setFormStatus}
          setModalOpen={setModalOpen}
        />
      </div>
    )
  } else if (formStatus === 'edit') {
    return (
      <div className='form-screen'>
        <VolunteerForm
          formStatus={formStatus}
          setFormStatus={setFormStatus}
          volunteerId={volunteerId}
          setVolunteerId={setVolunteerId}
        />
      </div>
    )
  }
}

Full React client repo HERE: https://github.com/Ricomitch/The-Door/tree/develop/client

I really appreciate any help.
Best,
Sean

hi sean, sorry to be slow to reply to you. i’ve asked a team mate who knows most about forms to take a look at this and give you his take!

Hi Perry -
Don’t worry - figured this out!!
Rookie mistake, as you might imagine. Changes to back end controllers were current in local development, but not deployment (on Heroku.).

Maybe a good lesson to pipe exceptions to the browser, to know source to blame.

Heh - sorry to cry wolf!

1 Like

no worries! thanks for letting us know :smiley: