如何使用带有重置按钮的Formik重置反应选择单输入

时间:2020-05-16 04:01:21

标签: reactjs react-select formik

我对React还是比较陌生的,尤其是对react-select和Formik都是陌生的。我有一个包含Input组件和三个Select组件的表单。当我只使用一个基本的isMulti按钮时,一次使用reset来选择多个选项的输入和两个选择都很好,但是单个select组件却没有。如果我检查values是什么为空,但是UI不能反映此更改。我尝试过:

利用resetForm(),将其设置为initialValues以及一个空对象。

使用onReset并从那里隐式调用resetForm

使用setFieldValue

的一些不同变体

我认为这可能是我设置initialValues的方式,但是现在我只是转了一圈,希望对此更有经验。

(PS-文档中的示例向您展示了如何使用带有复位按钮的Formik使用React-Select,但未提供非多重选择的示例。)

单选的名称为“已付费”,我使用值和标签属性包含了我认为正确的对象

简化的沙箱。所需的行为:点击“重置”会将选项重置为initialValues,并在用户界面中显示占位符文本。

https://codesandbox.io/s/peh1q

const costOptions = [
   { value: 'true', label: 'Paid' },
   { value: 'false', label: 'Free' },
];

Resources.propTypes = {
  initialValues: shape({
    category: array,
    q: string,
    languages: array,
    paid: string,
  }),
};

Resources.defaultProps = {
  initialValues: {
    category: [],
    q: '',
    languages: [],
    paid: '',
  },
};

       <Formik
          enableReinitialize
          initialValues={initialValues}
          onSubmit={(values, actions) => {
            handleSubmit(values, actions);
            actions.setSubmitting(true);
          }}
        >
          {({ isSubmitting }) => (
            <Form>
              <Field
                data-testid={RESOURCE_SEARCH}
                disabled={isSubmitting}
                type="search"
                name="q"
                label="Search Keywords"
                component={Input}
              />
              <div className={styles.formContainer}>
                <div className={styles.selectColumn}>
                  <Field
                    isDisabled={isSubmitting}
                    isMulti
                    placeholder="Start typing a category..."
                    label="By Category"
                    name="category"
                    options={allCategories}
                    component={Select}
                  />
                </div>

                <div className={styles.selectColumn}>
                  <Field
                    isDisabled={isSubmitting}
                    placeholder="Resource cost..."
                    label="By Cost"
                    name="paid"
                    options={costOptions}
                    component={Select}
                  />
                </div>

                <div className={styles.selectColumn}>
                  <Field
                    isDisabled={isSubmitting}
                    placeholder="Start typing a language..."
                    isMulti
                    label="By Language(s)"
                    name="languages"
                    options={allLanguages}
                    component={Select}
                  />
                </div>
              </div>
              <div className={styles.buttonGroup}>
                <Button disabled={isSubmitting} type="submit">
                  Search
                </Button>

                <Button disabled={isSubmitting} type="reset">
                  Reset
                </Button>
              </div>
            </Form>
          )}
        </Formik>

2 个答案:

答案 0 :(得分:2)

因此,我发布的代码(需要学习的地方)中实际上不需要修复的任何东西,但是在codesandbox中。

在Formik中使用的

Select组件如下所示:

import React from 'react';
import {
  arrayOf,
  bool,
  func,
  number,
  object,
  objectOf,
  oneOfType,
  shape,
  string,
} from 'prop-types';
import { ErrorMessage } from 'formik';
import Alert from 'components/Alert/Alert';
import Label from 'components/Form/Label/Label';
import ThemedReactSelect from './ThemedReactSelect';
import styles from './Select.module.css';

Select.propTypes = {
  field: shape({
    name: string.isRequired,
    value: oneOfType([string.isRequired, arrayOf(string.isRequired).isRequired]),
  }).isRequired,
  form: shape({
    // TODO: Resolve why multiselects can end up with touched: { key: array }
    // see ThemedReactSelect as well
    // touched: objectOf(bool).isRequired,
    touched: object.isRequired,
    errors: objectOf(string).isRequired,
    setFieldTouched: func.isRequired,
    setFieldValue: func.isRequired,
  }).isRequired,
  hasValidationStyling: bool,
  id: oneOfType([string, number]),
  isLabelHidden: bool,
  isMulti: bool,
  label: string.isRequired,
  options: arrayOf(shape({ label: string.isRequired, value: string.isRequired }).isRequired)
    .isRequired,
};

Select.defaultProps = {
  hasValidationStyling: true,
  id: undefined,
  isLabelHidden: false,
  isMulti: false,
};

export default function Select({
  field: { name, value: fieldValue },
  form: { errors, setFieldTouched, setFieldValue, touched },
  hasValidationStyling,
  id,
  isLabelHidden,
  isMulti,
  label,
  options,
  ...props // disabled, placeholder, etc.
}) {
  /**
   * @description handle changing of non-multi select
   * @param {string} selected
   */
  const onChangeSingle = selected => {
    setFieldValue(name, selected.value);
  };

  /**
   * @description handle changing of multi select
   * @param {string[]} selectedArray
   */
  const onChangeMulti = selectedArray => {
    if (selectedArray) {
      setFieldValue(
        name,
        selectedArray.map(item => item.value),
      );
    } else {
      setFieldValue(name, []);
    }
  };

  /**
   * @description Return the selected value as a string
   * @returns {string}
   */
  const getValueFromSingle = () => {
    return options.find(option => option.value === fieldValue);
  };

  /**
   * @description Return an array of selected values for multi selects
   * @returns {string[]}
   */
  const getValueFromMulti = () => {
    return options.filter(option => fieldValue.includes(option.value));
  };

  const handleBlur = () => {
    setFieldTouched(name);
  };

  const hasErrors = Boolean(errors[name]);

  // handlers and value depend on whether or not select allows for multiple selections.
  const value = isMulti ? getValueFromMulti() : getValueFromSingle();
  const onChangeHandler = isMulti ? onChangeMulti : onChangeSingle;

  return (
    <div className={styles.field}>
      <Label for={name} isHidden={isLabelHidden}>
        {label}
      </Label>

      <div className={styles.selectFeedbackGrouping}>
        <ThemedReactSelect
          {...props}
          hasErrors={hasErrors}
          hasValidationStyling={hasValidationStyling}
          isTouched={touched[name]}
          id={id || name}
          isMulti={isMulti}
          name={name}
          onBlur={handleBlur}
          onChange={onChangeHandler}
          options={options}
          value={value}
        />

        <ErrorMessage
          name={name}
          render={message => {
            return hasErrors ? (
              <Alert className={styles.errorMessage} type="error">
                {message}
              </Alert>
            ) : null;
          }}
        />
      </div>
    </div>
  );
}

首先,处理输入为handleOnChange并单击“ X”以清除选择内容时在isClearable={true}中传递的空值

 const onChangeSingle = selected => {
    setFieldValue(name, selected === null ? '' : selected.value);
  };

然后,为字段值做一个后备(在上面的ThemedReactSelect中)

<ThemedReactSelect
          {...props}
          hasErrors={hasErrors}
          hasValidationStyling={hasValidationStyling}
          isTouched={touched[name]}
          id={id || name}
          isMulti={isMulti}
          name={name}
          onBlur={handleBlur}
          onChange={onChangeHandler}
          options={options}
          value={value || ''}
        />

现在,单选功能与重置表单时的多选功能一样。

答案 1 :(得分:0)

您是否尝试过将1属性添加到单个值下拉列表中?

index