使用 Formik 的多个组件产生一个值
Multiple components to result in one value with Formik
我有 3 个 <select>
组件。在第一个组件中我有天数,在第二个组件中有月份,在第三个组件中有年份。这些组件充当一个日期选择器。我尝试用 Formik 的 connect
包装并使用 setFieldValue
和 setFieldError
,但在我以该形式编辑其他组件后错误消失。
如何解决才能使错误持续存在。如我所见,这种行为是 known.
class DateField extends Component {
constructor(props) {
super(props);
const value = props.value;
this.state = {
day: moment.utc(value).date(),
month: moment.utc(value).month(),
year: moment.utc(value).year(),
};
}
handleChange = e => {
const stateProp = e.target.name.split('.').pop();
this.setState(
{
[stateProp]: e.target.value,
},
() => {
const { formik } = this.props;
const date = this.dateFromState();
const error = this.props.validate(date);
formik.setFieldValue(this.props.name, date, false);
formik.setFieldError(this.props.name, error);
}
);
};
handleBlur = () => {
const { formik } = this.props;
const date = this.dateFromState();
const error = this.props.validate(date);
formik.setFieldTouched(this.props.name, true, false);
formik.setFieldError(this.props.name, error);
};
dateFromState() {
// returns date constructed from the state
}
render() {
const { formik, name } = this.props;
const error = getValueByPath(formik.errors, name);
return (
<div className="form-group">
<label>{this.props.label}</label>
<select
name={`${this.props.name}.day`}
value={this.state.day}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{
// options for days
}
</select>
<select
name={`${this.props.name}.month`}
value={this.state.month}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{
// options for months
}
</select>
<select
name={`${this.props.name}.year`}
value={this.state.year}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{
// options for years
}
</select>
{error && (
<div className="validation-message">
<span>{error}</span>
</div>
)}
</div>
);
}
}
const getValueByPath = (obj, path) => path.split('.').reduce((o, i) => o && o[i], obj);
export default connect(DateField);
我的建议是将组件与 formik 分离,让它提供日期并相应地处理更改。然后,您使用它的表单可以确定提供的日期是否有效,并将错误传递给您的受控组件以显示直到日期有效。这对于可重用性也很有帮助。
const DatePicker = ({ name, value, error, onChange, onBlur }) => {
const today = new Date(value);
const [day, setDay] = useState(today.getUTCDay());
const [month, setMonth] = useState(today.getUTCMonth());
const [year, setYear] = useState(today.getUTCYear());
useEffect() => {
const newDate = new Date([year, month, day]);
const target = { name, value: newDate };
onChange({ target });
}, [day, month, year]);
return (
//do your JSX here;
);
}
我有 3 个 <select>
组件。在第一个组件中我有天数,在第二个组件中有月份,在第三个组件中有年份。这些组件充当一个日期选择器。我尝试用 Formik 的 connect
包装并使用 setFieldValue
和 setFieldError
,但在我以该形式编辑其他组件后错误消失。
如何解决才能使错误持续存在。如我所见,这种行为是 known.
class DateField extends Component {
constructor(props) {
super(props);
const value = props.value;
this.state = {
day: moment.utc(value).date(),
month: moment.utc(value).month(),
year: moment.utc(value).year(),
};
}
handleChange = e => {
const stateProp = e.target.name.split('.').pop();
this.setState(
{
[stateProp]: e.target.value,
},
() => {
const { formik } = this.props;
const date = this.dateFromState();
const error = this.props.validate(date);
formik.setFieldValue(this.props.name, date, false);
formik.setFieldError(this.props.name, error);
}
);
};
handleBlur = () => {
const { formik } = this.props;
const date = this.dateFromState();
const error = this.props.validate(date);
formik.setFieldTouched(this.props.name, true, false);
formik.setFieldError(this.props.name, error);
};
dateFromState() {
// returns date constructed from the state
}
render() {
const { formik, name } = this.props;
const error = getValueByPath(formik.errors, name);
return (
<div className="form-group">
<label>{this.props.label}</label>
<select
name={`${this.props.name}.day`}
value={this.state.day}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{
// options for days
}
</select>
<select
name={`${this.props.name}.month`}
value={this.state.month}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{
// options for months
}
</select>
<select
name={`${this.props.name}.year`}
value={this.state.year}
onChange={this.handleChange}
onBlur={this.handleBlur}
>
{
// options for years
}
</select>
{error && (
<div className="validation-message">
<span>{error}</span>
</div>
)}
</div>
);
}
}
const getValueByPath = (obj, path) => path.split('.').reduce((o, i) => o && o[i], obj);
export default connect(DateField);
我的建议是将组件与 formik 分离,让它提供日期并相应地处理更改。然后,您使用它的表单可以确定提供的日期是否有效,并将错误传递给您的受控组件以显示直到日期有效。这对于可重用性也很有帮助。
const DatePicker = ({ name, value, error, onChange, onBlur }) => {
const today = new Date(value);
const [day, setDay] = useState(today.getUTCDay());
const [month, setMonth] = useState(today.getUTCMonth());
const [year, setYear] = useState(today.getUTCYear());
useEffect() => {
const newDate = new Date([year, month, day]);
const target = { name, value: newDate };
onChange({ target });
}, [day, month, year]);
return (
//do your JSX here;
);
}