У меня есть 2 отдельных вида.Оба они используют одну и ту же форму.Форма живет в модале.Форма отлично работает в первом представлении (Режим создания) .
Теперь я хочу добавить еще один, для (Режим редактирования) .Единственное отличие состоит в том, что в режиме редактирования нужны значения фактического элемента (в нашем случае пользователь) .
Я понимаю, как работают компоненты высшего порядка в целом.Но моя текущая конфигурация использует Redux, Formik and Yup
для получения данных, обработки форм и проверки соответственно.
Я попробовал несколько примеров в Интернете, но ни один из них не подходит для моего сценария.И здесь кроется проблема.Какую функциональность мне следует перейти к компоненту высшего порядка?
Функциональность первая: где должна жить действительная форма.Компонент или HOC?Code Below:
Должен ли я переместить его в HOC?Так как это точно такая же форма.Если да, то почему?
Функциональность 2: Я делаю проверку формы с Yup.Я перенес эту функциональность в HOC, но теперь я не могу передать ValidatioSchema компоненту формы.Code Below
:
Функциональность 3: Как работать с модалом.Модал немного хитрый.Я решил использовать его отдельно, на каждом отдельном экране.Это правильно или я должен включить его в 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);
Я понимаю, что это большой объем кода, который нужно проработать.Но я в растерянности.Не знаю, что я должен включать, где.
Мне нужны форма (Formik) и Yup, а также Redux в HOC.А затем добавить данные в зависимости от представления.Пожалуйста, мне действительно нужны рекомендации и примеры.Спасибо.