我有 2 个不同的视图。它们都使用相同的形式。表单存在于模态中。该表单在第一个视图(创建模式)中完美运行。
现在我想为(Edit Mode)添加另一个。唯一的区别是编辑模式需要实际项目的值(在我们的例子中是用户)。
一般来说,我了解高阶组件的工作原理。但我目前的配置Redux, Formik and Yup
分别用于获取数据、表单处理和验证。
我在网上尝试了一些示例,但没有一个适合我的情况。这就是问题所在。我应该将多少功能转移到高阶组件?
功能一:实际形式应该存在的地方。组件,还是 HOC?Code Below:
我应该在 HOC 中移动它吗?因为它是完全相同的形式。如果是,为什么?
功能 2:我正在使用 Yup 进行表单验证。我已将此功能移至 HOC,但现在,我无法将 ValidatioSchema 传递给表单组件。Code Below
:
功能3:如何处理Modal。模态有点棘手。我决定在每个单独的屏幕中单独使用它。这是正确的还是我应该将它包含在 HOC 中?
我的 HOC:
import React, { Component } from 'react';
import { withFormik } from 'formik';
import PropTypes from 'prop-types';
import * as Yup from 'yup';
import { createUser, updateUser } from './service';
import { listGroups } from '../groups/service';
const AddEditUserHOCForm = WrappedComponent => {
class ViewUser extends Component {
static propTypes = {
user: PropTypes.object,
onCancel: PropTypes.func,
onSave: PropTypes.func,
status: PropTypes.string,
values: PropTypes.object,
errors: PropTypes.object,
isSubmitting: PropTypes.bool,
handleChange: PropTypes.func,
handleSubmit: PropTypes.func,
setStatus: PropTypes.func
};
static defaultProps = {
user: {},
onCancel: () => { },
onSave: () => { },
status: '',
values: {},
errors: {},
isSubmitting: false,
handleChange: () => { },
handleSubmit: () => { },
setStatus: () => { }
};
state = {
groups: [],
isRetrievingData: false
};
componentDidMount() {
this.setState({
isRetrievingData: true
});
return new Promise([listGroups()])
.then(values => values.map(res => res.data))
.then(([groups]) => {
this.setState({
isRetrievingData: false,
groups
});
})
.catch(({ message = 'Could not retrieve data from server.' }) => {
this.setState({
isRetrievingData: false
});
this.props.setStatus(message);
});
}
handleCancel = () => {
const { onCancel } = this.props;
if (onCancel) {
onCancel();
}
};
render() {
return (
<WrappedComponent
{...this.props}
{...this.state}
onSubmit={this.handleSubmit}
onCancel={this.handleCanel}
/>
);
}
}
const UserValidationSchema = Yup.object().shape({
username: Yup.string('Provide a Username').required('Username is Required'),
password: Yup.string().email('Provide a Valid email Address'),
confirmPassword: Yup.string('Enter your password again')
.required('Password Confirmation is Required')
.oneOf([Yup.ref('password')], 'Passwords do not match')
});
const NewUserFormHOC = withFormik({
mapPropsToValues: ({ user }) => ({ ...user }),
UserValidationSchema,
handleSubmit: (values, { props, setSubmitting, setStatus }) => {
const saveUser = values.username ? updateUser : createUser;
return saveUser(values)
.then(() => {
setSubmitting(false);
setStatus('');
props.onSave(values);
props.onCancel();
})
.catch(({ message, response: { data } }) => {
setSubmitting(false);
setStatus(data || message);
});
},
displayName: 'ViewUser'
})(ViewUser);
return NewUserFormHOC;
};
export default AddEditUserHOCForm;
这是我的表单组件:
import React, { Component, Fragment } from 'react';
import { Formik, Form, Field } from 'formik';
import PropTypes from 'prop-types';
import AddEditUserHOCForm from './components/AddEditUserHOC'
import LensesSelect from './data/ReactSelectComponent';
import formPropTypes from '../constants/formPropTypes';
import { listGroups } from '../groups/service';
class UserCreateForm extends Component {
static propTypes = {
...formPropTypes,
username: PropTypes.string,
email: PropTypes.string,
password: PropTypes.string,
confirmPassword: PropTypes.string,
groupSelect: PropTypes.func
};
static defaultProps = {
email: ''
};
state = {
type: 'password',
groups: []
};
componentDidMount() {
this.fetchListGroups();
}
fetchListGroups = () => {
listGroups().then(({ data }) => {
this.setState({ groups: data });
});
};
mapListGroupToSelect = () => {
const { groups } = this.state;
return groups.map(group => ({
label: group.name,
value: group.name
}));
};
togglePasswordMask = e => {
const { type } = this.state;
e.preventDefault();
this.setState(prevState => ({
passwordIsMasked: !prevState.passwordIsMasked,
type: type === 'password' ? 'input' : 'password'
}));
};
selectOnChangeCallback = response => {
// eslint-disable-next-line no-console
console.log('selectOnChangeCallback', response);
};
render() {
const { type } = this.state;
const selectData = this.mapListGroupToSelect();
return (
<Fragment>
<Formik
initialValues={{
username: '',
email: '',
password: '',
confirmPassword: ''
}}
// validationSchema={createUserValidationSchema}
onSubmit={values => {
// same shape as initial values
console.log(values);
}}
>
{({ errors, touched }) => (
<Form>
<div className="my-3">
<label>
Username <span className="text-danger">*</span>
</label>
<Field name="username" type="text" className="form-control rounded-0" />
{errors.username && touched.username ? (
<div className="text-danger">{errors.username}</div>
) : null}
</div>
<div className="my-3">
<label>email</label>
<Field name="email" type="email" className="form-control rounded-0" />
{errors.email && touched.email ? (
<div className="text-danger">{errors.email}</div>
) : null}
</div>
<div className="my-3">
<label>
Password <span className="text-danger">*</span>
</label>
<div className="d-flex align-items-center">
<Field type={type} name="password" className="form-control rounded-0 mr-2" />
<span
className={type === 'password' ? 'fa fa-eye fa-lg' : 'fa fa-eye-slash fa-lg'}
onClick={this.togglePasswordMask}
/>
</div>
{errors.password && touched.password ? (
<div className="text-danger">{errors.password}</div>
) : null}
</div>
<div className="my-3">
<label>
Confirm Password <span className="text-danger">*</span>
</label>
<Field name="confirmPassword" type={type} className="form-control rounded-0" />
{errors.confirmPassword && touched.confirmPassword ? (
<div className="text-danger">{errors.confirmPassword}</div>
) : null}
</div>
<div className="my-3">
<label>
Select Group <span className="text-danger">*</span>
</label>
<ReactSelectComponent
isMulti={false}
options={selectData}
onChangeCallback={this.selectOnChangeCallback}
/>
</div>
<button type="submit" className="btn btn-primary rounded-0 float-right my-5">
<span className="mx-2">Create User</span>
</button>
</Form>
)}
</Formik>
</Fragment>
);
}
}
export default AddEditUserHOCForm(UserCreateForm);
我知道这是很多代码需要通过。但我不知所措。真的不知道我应该在哪里包括什么。
对我来说,我需要 form(Formik) 和 Yup,以及 HOC 上的 Redux。然后根据视图添加数据。请我真的需要一些指导和一些例子。谢谢你。