使用Formik表单的React-datepicker

时间:2019-05-26 09:42:05

标签: reactjs formik react-datepicker

我正在尝试以Formik形式使用react-datepicker。

我有:

import DatePicker from "react-datepicker";
import "react-datepicker/dist/react-datepicker.css";


class Fuate extends React.Component {
    state = {
        dueDate: new Date()

    }

<Formik
                initialValues={initialValues}
                validationSchema={Yup.object().shape({
                    title: Yup.string().required("A title is required "),
                })}

                onSubmit={this.handleSubmit}

                render={({ 
                    errors, 
                    status, 
                    touched, 
                    setFieldValue,
                    setFieldTouched, 
                    handleChange, 
                    handleBlur,
                    handleSubmit, 
                    isSubmitting, 
                    dirty, 
                    values 
                }) => {

                return (
                    <div>
            ...

<DatePicker
                                            name={'dueDate'}
                                            value={values['dueDate']}
                                            onChange={e => setFieldValue('dueDate', e)}
                                        />
                                        <DatePicker
                                        style={{ width: 180 }}
                                        date={values.dueDate}
                                        mode="date"
                                        format="YYYY-MM-DD"
                                        minDate={Date.now.toString()}
                                        maxDate="2050-06-01"
                                        confirmBtnText="Confirm"
                                        cancelBtnText="Cancel"
                                        showIcon={false}
                                        customStyles={{
                                            dateInput: {
                                            marginLeft: 0,
                                            borderColor: "#fff"
                                            }
                                        }}
                                        onDateChange={date => setFieldValue("dueDate", date)}
                                        onTouch={setFieldTouched}
                                        />

对于这两个选项,表单都会呈现出来,我可以在日历上选择一个日期,但是它不会出现在框中,并且状态值不会随选择内容而更新。

控制台中没有错误,但警告显示:

  

从v2.0.0-beta.1 date-fns开始不接受字符串作为   论点。请使用parseISO解析字符串。看到:   toDate @ index.js:45

我尝试设置初始状态:

dueDate: new Date().toISOString(),

但这没什么区别。

我已经看到很多关于使用Antd的日期选择器进行设置的帖子,但是找不到有关如何使用react-datepicker进行操作的说明。

5 个答案:

答案 0 :(得分:7)

更新为Dani Vijay's answer
这使用了Formik v2中的useFielduseFormikContext,以简化组件的使用。

DatePicker.jsx:

import React from "react";
import { useField, useFormikContext } from "formik";
import DatePicker from "react-datepicker";

export const DatePickerField = ({ ...props }) => {
  const { setFieldValue } = useFormikContext();
  const [field] = useField(props);
  return (
    <DatePicker
      {...field}
      {...props}
      selected={(field.value && new Date(field.value)) || null}
      onChange={val => {
        setFieldValue(field.name, val);
      }}
    />
  );
};

用法(有关完整的表单声明,请参见Dani的答案):

...
<DatePicker name="date" />
...

Code at codesandbox

答案 1 :(得分:0)

react-datepicker可以与Formik一起使用,方法是利用setFieldValue

this.$refs.componentB

CodeSandbox演示here

答案 2 :(得分:0)

我从您的代码中看到的是DatePicker不在Formik内部。在React.js中,我们总是创建可重用的组件,因此保持代码干净且易于测试。为了能够在代码中使用DatePicker,请创建一个单独的文件,为Datepicker编写代码,并将其呈现为Field的一部分。这是您应该如何实施。

//First let's start with structure of Formik.
import PortDate from "./form/PortDate";
//define your components in a different directory. I named it form
const CreateForm = props => (
    <div>
      <Formik
        initialValues={{"your initial values"}}
        validate={your validation function here}
        onSubmit={values => {
          return props.onSubmit(values);
        }}
      >
        {({ isSubmitting }) => (
          <Form>     
            <Field name="startDate" component={DatePicker} label="Start Date" />

            <Field
              name="endDate"
              component={DatePicker}
              label="End Date"
              canBeDisabled={true}
            />

          </Form>
        )}
      </Formik>
    </div>
  );

现在在其他组件中,让我们实现Datepicker逻辑。     //要添加样式时,请使用reactstrap而不是bootstrap

import { FormGroup, Label } from "reactstrap";
class DatePicker extends React.Component {
    constructor(props) {
      super(props);
      this.state = {
        dueDate: new Date(),
      };
      this.handleChange = this.handleChange.bind(this);
    }
    setFieldValueAndTouched(date, touched) {
      const { setFieldValue, setFieldTouched } = this.props.form;
      const { name } = this.props.field;
      setFieldValue(name, date, true); //field,value,shouldValidate
      setFieldTouched(name, touched, true); //field,touched,shouldValidate
    }
    handleChange(date) {

      this.setState(() => ({ dateValue: date }));
      this.setFieldValueAndTouched(date, true);    }

    render() {
      const { dueDate } = this.state;
      const {
        label,
        field,
        form: { touched, errors },
      } = this.props;
      // field and form props are passed to this component automatically because we render this inside component of the Field. 
      return (
        <FormGroup>
          <Label>{label}</Label>
          <div className="input-group">

              <DatePicker

                selected={dueDate}
                onChange={this.handleChange}
                peekNextMonth
                showMonthDropdown
                showYearDropdown
                maxDate={new Date()}
                dropdownMode="select"
              />

          </div>
        </FormGroup>
      );
    }
  }

  export default DatePicker;

答案 3 :(得分:0)

如何使其适用于日期范围选择器:

const [startDate, setStartDate] = useState(new Date());
const [endDate, setEndDate] = useState(new Date());
const { setFieldValue } = useFormikContext();
const [field] = useField({ name: name, value: startDate });
const [field2] = useField({ name: name2, value: endDate });

<GroupContainer>
 <DatePicker
    {...field}
    onFocus={() => setFocusStart(true)}
    onCalendarClose={() => setFocusStart(false)}
    selected={(field.value && new Date(field.value)) || null}
    onChange={(val) => {
                    setStartDate(val);
                    setFieldValue(field.name, val);
                }}
    dateFormat="dd.MM.yyyy" 
    selectsStart                            
    minDate={new Date()}                                
            />
</GroupContainer>

<GroupContainer>
  <DatePicker
    {...field2}
    onFocus={() => setFocusEnd(true)}
    onCalendarClose={() => setFocusEnd(false)}          
    selected={(field2.value && new Date(field2.value)) || null}
    onChange={(val) => {
            setEndDate(val);
            setFieldValue(field2.name, val);
                }}
    dateFormat="dd.MM.yyyy"         
    selectsEnd
    minDate={new Date()}        
            />
</GroupContainer>

那么:

<ReactDatePicker name="arrivalDate" name2="departureDate" />

答案 4 :(得分:0)

更新到Dani Vijay and ToolmakerSteve's answers

直接使用 setValue 而不是 setFieldValue。基于@asologor's comment

import React from "react";
import { useField } from "formik";
import DatePicker from "react-datepicker";

export const DatePickerField = ({ ...props }) => {
  const [field, , { setValue }] = useField(props);
  return (
    <DatePicker
      {...field}
      {...props}
      selected={(field.value && new Date(field.value)) || null}
      onChange={(val) => {
        setValue(val);
      }}
    />
  );
};

注意:此方法允许您将 Formik 与 react-datepicker 一起使用,但它也适用于其他 UI 库,例如 Material-UIAnt Design