onReset causes RangeError: Maximum call stack size exceeded

onReset causes RangeError: Maximum call stack size exceeded

在我的 React Redux 应用程序中,我使用 react-bootstrap(v^1.6.0) 和 Formik(v2.2.6) 构建过滤器表单。

除重置处理外一切正常。单击重置按钮后,我得到

RangeError: Maximum call stack size exceeded
resetForm
src/Formik.tsx:347
  344 |   }
  345 | }, [validateOnMount, validateFormWithHighPriority]);
  346 | 
> 347 | const resetForm = React.useCallback(
      | ^  348 |   (nextState?: Partial<FormikState<Values>>) => {
  349 |     const values =
  350 |       nextState && nextState.values
View compiled
onResetAction [as onReset]
src/use-cases/schools-page/declarations-page/components/DeclarationsFilter.tsx:42
  39 | }
  40 | 
  41 | const onResetAction = (values: FilterValues, helpers: FormikHelpers<FilterValues>) => {
> 42 |   helpers.resetForm()
     | ^  43 |   onFilterChange({})
  44 | }
  45 | 

下面是我的代码

import React from 'react'
import { Declaration } from 'store/declarations/reducer'
import { DeclarationsFilters } from 'use-cases/schools-page/declarations-page/types'
import { Button, Col, Form } from 'react-bootstrap'
import { uniq } from 'lodash'
import { Formik, FormikHelpers } from 'formik'

type Props = {
  filters: DeclarationsFilters
  allDeclarations: Declaration[]
  onFilterChange: (filters: DeclarationsFilters) => void
}

type FilterValues = {
  surname: string
  classNumber: string
  className: string
}

const all = 'wszystkie'

export const DeclarationsFilter: React.FC<Props> = ({ filters, allDeclarations, onFilterChange }): JSX.Element => {
  const allClasses = uniq(allDeclarations.map((declaration) => declaration.classNumber))
  const allClassNames = uniq(allDeclarations.map((declaration) => declaration.className))

  const onSearch = (values: FilterValues, helpers: FormikHelpers<FilterValues>) => {
    helpers.setSubmitting(true)
    const changedFilters: DeclarationsFilters = {
      surname: values.surname,
      selectedClass: values.classNumber === all ? undefined : parseInt(values.classNumber, 10),
      selectedClassName: values.className === all ? undefined : values.className
    }
    onFilterChange(changedFilters)
    helpers.setSubmitting(false)
  }

  const onResetAction = (values: FilterValues, helpers: FormikHelpers<FilterValues>) => {
    helpers.resetForm()
    onFilterChange({})
  }

  return (
    <Formik
      initialValues={{
        classNumber: filters.selectedClass?.toString() || all,
        className: filters.selectedClassName || all,
        surname: filters.surname || ''
      }}
      onSubmit={onSearch}
      onReset={onResetAction}
    >
      {({ handleSubmit, isSubmitting, handleChange, handleBlur, values, handleReset }) => (
        <Form noValidate onSubmit={handleSubmit} onReset={handleReset}>
          <Form.Row>
            <Col>
              <Form.Group controlId="declarationsFilter.surname">
                <Form.Label>Nazwisko</Form.Label>
                <Form.Control
                  type="text"
                  placeholder="..."
                  onBlur={handleBlur}
                  name="surname"
                  onChange={handleChange}
                  value={values.surname}
                />
              </Form.Group>
            </Col>
            <Col>
              <Form.Group controlId="declarationsFilter.classNumber">
                <Form.Label>Klasa:</Form.Label>
                <Form.Control
                  as="select"
                  onBlur={handleBlur}
                  name="classNumber"
                  onChange={handleChange}
                  value={values.classNumber}
                >
                  <option>{all}</option>
                  {allClasses.map((classNumber) => (
                    <option>{classNumber}</option>
                  ))}
                </Form.Control>
              </Form.Group>
            </Col>
            <Col>
              <Form.Group controlId="declarationsFilter.className">
                <Form.Label>Nazwa klasy:</Form.Label>
                <Form.Control
                  as="select"
                  onBlur={handleBlur}
                  name="className"
                  onChange={handleChange}
                  value={values.className}
                >
                  <option>{all}</option>
                  {allClassNames.map((classNumber) => (
                    <option>{classNumber}</option>
                  ))}
                </Form.Control>
              </Form.Group>
            </Col>
          </Form.Row>
          <Form.Row>
            <Button variant="primary" type="submit" disabled={isSubmitting}>
              Filtruj
            </Button>
            <Button variant="primary" type="reset">
              Resetuj
            </Button>
          </Form.Row>
        </Form>
      )}
    </Formik>
  )
}

方法'onFilterChange'目前什么都不做。以后会更新redux store

有人理解这种行为吗?谢谢!

您似乎创建了一个无限循环:

  1. 点击重置
  2. 触发 Formik onReset,调用 onResetAction
  3. onResetAction 呼叫 helper.resetForm()
  4. ...强制重置表单,
  5. 哪个触发了 Formik onReset 和你身边永远

要修复它,请不要从 onReset 调用 resetForm。如果你想连接一个重置按钮,你可以直接将你的 onResetAction 挂接到普通(即不是 'reset')按钮的 onClick 处理程序。