Прежде всего, я уже нашел способ добиться этого, но у меня есть оговорки в отношении этого подхода, поскольку я использую объект состояния класса React, которого я хотел избежать.
Formik определен внутри функции рендеринга компонента класса React, поэтому я не могу делать вещи setFieldValue или Reset_Form программно. В качестве обходного пути я в основном собираю объект ref из formik во время рендера и сохраняю его в состоянии. Затем я использую объект ref в событии изменения моего раскрывающегося списка, как показано в функции On_Change_Select_Dropdown файла form.tsx. Объект ref formik позволяет мне использовать его встроенные функции для внешнего управления формой.
Другой подход, который работает, - это модификация объекта значений Formik. Но разве это хорошая идея?
Я нахожусь на начальном уровне в response.js, поэтому мне нужно экспертное мнение о недостатках этого подхода и любых возможных альтернативах, которые не требуют масштабного рефакторинга кода, так как он довольно близок к завершению.
form.tsx
render() {
return (
<div className="app">
<h1 style={{ textAlign: "center" }}>Cash Debt Report</h1>
<Formik
onSubmit={(e, { setSubmitting }) => {this.On_Submit(e, setSubmitting)}}
onReset={e => this.On_Reset(e)}
enableReinitialize={true}
validateOnChange={false}
ref={(e) => { this.state.formik = e }}
initialValues={this.Get_Initial_Values(fields)}
render={({ values, errors, isSubmitting, touched }) => {
this.On_Touched(touched, values);
const errorMessageShow = Object.keys(errors).length > 0 ? 'error' : 'hidden';
return (
<div>
<Form>
<div>
{this.Render_Fields(fields, values)}
</div>
{this.Render_Grid_Accounts('cash_accounts', values)}
</Form>
</div>
}
}
);
}
Render_Fields(inputs, values) {
return (
Object.keys(inputs).map((field_key) => {
let input = inputs[field_key];
if (input.auto_render) {
if (input.type === 'select') {
return this.Render_Select(input.name, input.label, input.name, values);
}
else if (input.type === 'checkbox') {
return this.Render_Check_Box(input.name, input.value, input.label, values);
}
else if (input.type === 'textarea') {
return this.Render_Text_Area(input.name, input.value, input.label, values);
}
else if (input.type === 'text') {
return this.Render_Text(input.name, input.value, input.label, values);
}
else { return }
}
else { return }
})
);
}
On_Change_Select_Dropdown(e,values) {
let url = sp_config.paths.api + "/_api/web/lists/getbytitle('" +
sp_config.lists.cash_debt_acc.title + "')/items"+
"?$select=*,Company/Id,Currency/Id" +
"&$expand=Company,Currency" +
"&$orderby=Created desc"
"&$top=1" +
"&$filter=Division eq '" + division + "' and
Company/Id eq '" + company + "'";
Get(url).then((res) => {
let results = res.data['d'].results;
let cash_accounts: object[] = [];
let acc_obj;
if (results.length > 0) {
results.map(v => {
acc_obj = acc_obj_cash;
acc_obj.account_no = v.AccountNo;
cash_accounts.push(acc_obj) : debt_accounts.push(acc_obj);
});
//Repopulate Field Array with new items fetched from SharePoint
this.state.formik['setFieldValue']('cash_accounts', [acc_obj_cash]);
//The following approach works but I have
//I am not sure if modifying the values object of formik is
//a good idea
//values['cash_account'] = [acc_obj_cash]
}
});
}
fields.tsx
export const acc_obj_cash = {
category: 'Cash', bank_name: '',
account_type: '', account_no: '',
book_balance: '', bank_balance: '',
outstanding_bal: '',
variance: '0',
currency: ''
};
export const fields = {
division: { label: 'Division', type: 'select', name: 'division', value: '', auto_render: true, read_only: false },
cash_accounts:{
label: ['Account Type', 'Bank Name', 'Account No', 'Book Balance', 'Bank Balance'],
heading: ["Cash Accounts"],
name: 'cash_accounts',
type: 'array',
auto_render: true,
read_only: ['variance'],
value: new Array(2).fill(acc_obj_cash)
},
};
export default fields;