0
votes

Making a form with react + formik and wanting to use hooks to handle the child components state. When I hook up (haha) my hookified component to my form, the formik onChange handler does not fire as expected.

Form Code

... snip ...
  const classes = useStyles()
  return (
    <div>
      <FieldArray
        name='sessions'
        render={arrayHelpers => (
          <div>
            {values.sessions.map((data, i) => {
              return (
                <div className={classes.formControl} key={i}>
                  <TextField
                    margin='dense'
                    variant='outlined'
                    error={shouldShowError(
                      errors,
                      touched,
                      `sessions.${i}.name`
                    )}
                    style={{ display: 'flex', flex: 1 }}
                    value={values.sessions[i].name}
                    label={I18n.t('sessions.name.label')}
                    name={`sessions.${i}.name`}
                    onChange={handleChange}
                    onBlur={() => setFieldTouched(`sessions.${i}.name`)}
                  />
                  <DaysofWeek
                    value={values.sessions[i].days}
                    label={I18n.t('sessions.days.label')}
                    name={`sessions.${i}.days`}
                    onChange={handleChange}
                  />
... snip ...

When I replace the onChange line in DaysOfWeek with {data =>console.log(data)} I see the data I expect in the console.

I should also note that the TextField component in this form updates formik correctly.

For reference, heres the DaysOfWeek component code:

import React from 'react'
import { makeStyles } from '@material-ui/core/styles'
import FormControl from '@material-ui/core/FormControl'
import FormGroup from '@material-ui/core/FormGroup'
import FormControlLabel from '@material-ui/core/FormControlLabel'
import FormLabel from '@material-ui/core/FormLabel'
import Checkbox from '@material-ui/core/Checkbox'
import { symmetricDifference } from 'ramda'

const useStyles = makeStyles(theme => ({
  root: {
    display: 'flex'
  },
  formControl: {
    margin: theme.spacing(0)
  }
}))

export default function DaysofWeek ({ days = [], label = '', onChange }) {
  const classes = useStyles()
  const [stateDays, setState] = React.useState(days)

  const handleChange = value => _event => {
    let updatedDays = symmetricDifference([value], stateDays).sort()
    setState(updatedDays)
    onChange(updatedDays)
  }

  const staticDays = [
    [ 0, 'Sun' ],
    [ 1, 'Mon' ],
    [ 2, 'Tue' ],
    [ 3, 'Wed' ],
    [ 4, 'Thu' ],
    [ 5, 'Fri' ],
    [ 6, 'Sat' ]
  ]

  return (
    <div className={classes.root}>
      <FormControl component='fieldset' className={classes.formControl} >
        <FormLabel component="legend">{label}</FormLabel>
       { staticDays.map(([dayNum, dayLabel]) => 
        <FormGroup key={dayNum}>
          <FormControlLabel
            control={
              <Checkbox checked={stateDays.includes(dayNum)} onChange={handleChange(dayNum)} />
            }
            label={dayLabel}
          />
        </FormGroup>
       )}
      </FormControl>
    </div>
  )
}

Relevant bits of package.json:

    "@material-ui/core": "^4.3",
    "@material-ui/icons": "^4.2",
    "@material-ui/pickers": "^3.2.4",
    "classnames": "^2.2.6",
    "date-fns": "^2.0.1",
    ....
    "formik": "2.0.1-rc.13",
     ....
    "react": "^16.8.6",
    "react-apollo": "^2.5.5",
    "react-dom": "^16.8.6",
    "react-icons": "^3.6.1",
.....

How do I get the onChange from formik to update my formik state?

1
Try using useEffect with [stateDays, setState, onChange] as dependency. Also install npmjs.com/package/eslint-plugin-react-hooks#installation to see if you have any violations or warningRikin

1 Answers

0
votes

The actual problem was the onChange handler in the DaysofWeek field in the formik form.

I should have used setFieldValue from formik: onChange={data => setFieldValue(sessions.${i}.days, data)}