首页 > 解决方案 > 使用 Formik、React 验证自定义表单字段

问题描述

我正在使用 Formik 和 Yup 进行表单验证,

我在表单中使用了自定义表单字段(Algolia 即时搜索),但无法验证

我尝试了 2 个选项,我认为选项 2 很有希望,但是有一个问题。

选项 1:如下所示,我尝试将自定义表单字段 ( <AlgoliaSearch />) 包装在表单项中,就像我对手机号码字段所做的那样,以实现类似的验证。事实证明它不起作用,即即使填写了该字段也会显示错误消息。

选项 2:当用户在自定义表单字段 ( <AlgoliaSearch />) 中设置值时,我在标准输入字段中设置相同的值(在下面的代码中查找标准输入字段),当我单击提交时,formik 无法识别字段 (STANDARD INPUT FIELD) 已填写(尽管它是以编程方式填写的)。这可能是因为 formik 假设该字段没有被触及,因此它没有被填充。要解决此问题,我需要知道如何以编程方式设置已使用Formik触摸该字段。

在 form.js 中

const [selectedValue, setSelectedValue] = React.useState('');
  const handleSearchValue = _selectedVlue => {
    console.log(_selectedValue);
    setSelectedValue(_selectedValue);
  };

const validationSchema = Yup.object({
mobileNumber: Yup.string()
  .required()
  .min(10)
  .label('Mobile number'),
searchValue: Yup.string()
  .required()
  .label('Search value'),
selectedValue: Yup.string()
  .required()
  .label('Selected value')

return (
<>
  <Formik
    initialValues={{
      mobileNumber: '',
      searchValue: '',
      selectedValue:''
    }}
    onSubmit={handleSubmit}
    validationSchema={validationSchema}
    setFieldTouched={('selectedDoctor', true, true)}
  >
    <Form style={{ maxWidth: '250px', margin: '50px' }}>
     
      <Form.Item name="mobileNumber" hasFeedback={true} showValidateSuccess={true}>
        <Text>Mobile number</Text>
        <Input
          size="large"
          name="mobileNumber"
        />
      </Form.Item>

      {/* CUSTOM FORM FIELD */}
      <Form.Item name="searchValue" hasFeedback={true} showValidateSuccess={true}>
        <AlgoliaSearch searchValue={handleSearchValue} />
      </Form.Item>
      
      {/* STANDARD INPUT FIELD */}
      <Form.Item name="selectedValue" hasFeedback={true} showValidateSuccess={true}>
        <Input name="selectedValue" value={selectedValue} user />
      </Form.Item
    </Form>
 </Formik>
</>
);

AlgoliaSearch.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import algoliasearch from 'algoliasearch/lite';
import { InstantSearch, Configure, Hits, Highlight, connectSearchBox } from 'react-instantsearch-dom';
import Autocomplete from './Autocomplete';
import './Algolia.css';

// References
// Github, Autocomplete code: https://github.com/algolia/doc-code-samples/tree/master/React%20InstantSearch/autocomplete-results-page/src
// Algolia, autocomplete explained: https://www.algolia.com/doc/guides/building-search-ui/resources/ui-and-ux-patterns/in-depth/autocomplete/react/#overview

//const VirtalSearchBox = connectSearchBox(() => null);

const searchClient = algoliasearch('B1G2GM9NG0', 'aadef574be1f9252bb48d4ea09b5cfe5');

class AlgoliaSearch extends Component {
  state = {
    query: '',
  };

  onSuggestionSelected = (_, { suggestion }) => {
    this.setState({
      query: suggestion.name,
    });
    console.log('Setting suggestion.name: ' + suggestion.name);
    this.props.searchValue(suggestion.name);
  };

  onSuggestionCleared = () => {
    this.setState({
      query: '',
    });
  };

  render() {
    const { query } = this.state;

    return (
      <div>
        {/* <h1>React InstantSearch - Results page with autocomplete</h1> */}
        <InstantSearch indexName="demo_ecommerce" searchClient={searchClient}>
          <Configure hitsPerPage={3} />
          <Autocomplete
            onSuggestionSelected={this.onSuggestionSelected}
            onSuggestionCleared={this.onSuggestionCleared}
          />
        </InstantSearch>
      </div>
    );
  }
}

function Hit(props) {
  return (
    <div>
      <Highlight attribute="name" hit={props.hit} />
    </div>
  );
}

Hit.propTypes = {
  hit: PropTypes.object.isRequired,
};

export default AlgoliaSearch;

在 Autocomplete.js 中

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Highlight, connectAutoComplete } from 'react-instantsearch-dom';
import AutoSuggest from 'react-autosuggest';

class AutoComplete extends Component {
  static propTypes = {
    hits: PropTypes.arrayOf(PropTypes.object).isRequired,
    currentRefinement: PropTypes.string.isRequired,
    refine: PropTypes.func.isRequired,
    onSuggestionSelected: PropTypes.func.isRequired,
    onSuggestionCleared: PropTypes.func.isRequired,
  };

  state = {
    value: this.props.currentRefinement,
  };

  onChange = (_, { newValue }) => {
    if (!newValue) {
      this.props.onSuggestionCleared();
    }

    this.setState({
      value: newValue,
    });
  };

  onSuggestionsFetchRequested = ({ value }) => {
    this.props.refine(value);
  };

  onSuggestionsClearRequested = () => {
    this.props.refine();
  };

  getSuggestionValue(hit) {
    return hit.name;
  }

  renderSuggestion(hit) {
    return <Highlight attribute="name" hit={hit} tagName="mark" />;
  }

  render() {
    const { hits, onSuggestionSelected } = this.props;
    const { value } = this.state;

    const inputProps = {
      placeholder: 'Search for a doctor...',
      onChange: this.onChange,
      value,
    };

    return (
      <AutoSuggest
        suggestions={hits}
        onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
        onSuggestionsClearRequested={this.onSuggestionsClearRequested}
        onSuggestionSelected={onSuggestionSelected}
        getSuggestionValue={this.getSuggestionValue}
        renderSuggestion={this.renderSuggestion}
        inputProps={inputProps}
        name="selectedDoctor"
      />
    );
  }
}

export default connectAutoComplete(AutoComplete);

标签: reactjsalgoliaformikyup

解决方案


推荐阅读