React Hook Forms - 预填充字段数组不起作用
React Hook Forms - Pre-populate Fields Array Not Working
我是 React Hook Forms 的新手,除了在传入数据的编辑屏幕上使用 useFieldArray
显示 fields
之外,我一切正常。例如,我有以下:
TicketForm.js
import { useForm, useFieldArray, Controller } from 'react-hook-form';
import {
CCard,
CCardHeader,
CCollapse,
CCardBody,
CRow,
CCol,
CSidebar,
CSpinner,
CForm,
CFormGroup,
CInputCheckbox,
CFormText,
CTextarea,
CInput,
CInputFile,
CLabel,
CButton,
CButtonToolbar,
CButtonGroup,
CSelect
} from '@coreui/react';
import CIcon from '@coreui/icons-react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import Input from '../../base/forms/input';
import Select from '../../base/forms/select';
import TextArea from '../../base/forms/text_area';
import Checkbox from '../../base/forms/check_box';
import LineItems from './line_items';
import Attachments from './attachment_items';
const TicketHookForm = props => {
let ticket = props.ticket;
const ticketData = Object.keys(ticket).length ? {
defaultValues: {
line_items_attributes: [...ticket.line_items],
attachments_attributes: [...ticket.attachments]
}
} : {};
console.log('ticket data is', ticketData);
const { setValue, control, handleSubmit, watch } = useForm(ticketData);
const stores = useSelector(state => state.referenceData.stores);
const categories = useSelector(state => state.referenceData.categories);
const history = useHistory();
const formatReferenceData = (data, selectedId) => {
return data.map(item => <option key={item.id} value={item.id} selected={item.id === selectedId}>{item.name}</option>);
}
const submit = (data) => {
console.log('data', data);
props.onSubmit(data);
}
return (
<CRow>
<CCol xs={12}>
<CForm onSubmit={(e) => {
e.preventDefault();
handleSubmit(submit)()
}} method="post" encType="multipart/form-data">
<CFormGroup row>
<CCol xs={3}>
<CLabel htmlFor="line_items">Line Items</CLabel>
</CCol>
<CCol xs={9}>
<LineItems control={control} />
</CCol>
</CFormGroup>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>Additional Information</CCardHeader>
<CCardBody>
<CFormGroup row>
<CCol xs={3}>
<CLabel htmlFor="attachments">Attachments</CLabel>
</CCol>
<CCol xs={9}>
<Attachments control={control} setValue={setValue} />
</CCol>
</CFormGroup>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<CButton type="submit" color="primary"><CIcon name="cil-user" /> {props.ticketId ? 'Update' : 'Create'} Check Request</CButton>
<CButton type="reset" color="danger" onClick={() => history.goBack()}><CIcon name="cil-ban" /> Cancel</CButton>
</CCardHeader>
</CCard>
</CForm>
</CCol>
</CRow>
)
}
TicketHookForm.defaultProps = {
ticket: {}
}
export default TicketHookForm;
从上面的 console.log 中,我看到 ticketData
设置正确。例如,我有这个输出:
ticket data is {
defaultValues:
attachments_attributes: [{…}]
line_items_attributes: [{id: 8, description: "333", store: "Holman Cadillac", store_id: 2, account: "1", …}]
}
}
如果我注销 control
是什么,我也会注意到一切都是空的:
control is {
fieldArrayDefaultValuesRef: {
current: {
attachments_attributes: [],
line_items_attributes: []
}
}
然后,我有这个文件LineItems.js
import { useFieldArray } from 'react-hook-form';
import {
CFormGroup,
CRow,
CLabel,
CButton,
CCol
} from '@coreui/react';
import Input from '../../base/forms/input';
import Select from '../../base/forms/select';
import { useSelector } from 'react-redux';
const LineItems = props => {
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
control: props.control,
name: 'line_items_attributes'
});
console.log('fields are ', fields);
const stores = useSelector(state => state.referenceData.stores);
const formatStores = () => {
return stores.map(item => <option key={item.id} value={item.id}>{item.name}</option>);
}
return (
<section className="line-item">
{fields.map((item, index) => (
<div key={item.id}>
<CFormGroup row>
<CCol xs={4}>
<CLabel htmlFor="store">Store</CLabel>
<Select control={props.control} defaultValue={item.store_id} id="store-select" name={`line_items_attributes[${index}].store_id`} options={formatStores(stores)} control={props.control} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="description">Description</CLabel>
<Input control={props.control} defaultValue={item.description} id="description" name={`line_items_attributes[${index}].description`} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="control_1">Control 1</CLabel>
<Input control={props.control} defaultValue={item.control} id="control_1" name={`line_items_attributes[${index}].control`} />
</CCol>
</CFormGroup>
<CFormGroup row>
<CCol xs={4}>
<CLabel htmlFor="account">Account</CLabel>
<Input control={props.control} defaultValue={item.account} name={`line_items_attributes[${index}].account`} id="account" />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="amount">Amount</CLabel>
<Input control={props.control} defaultValue={item.amount} type="number" id="amount" name={`line_items_attributes[${index}].amount`} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="control_2">Control 2</CLabel>
<Input control={props.control} defaultValue={item.control2} name={`line_items_attributes[${index}].control2`} id="control_2" />
</CCol>
</CFormGroup>
<CRow>
<CCol xs={12} className="text-right"><CButton color="danger" onClick={() => remove(index)}>Remove</CButton></CCol>
</CRow>
</div>
))}
<CButton color="primary" variant="outline" onClick={() => append({})}>Add Line</CButton>
</section>
)
}
export default LineItems;
Input.js
import {
CInput
} from '@coreui/react';
import { Controller } from 'react-hook-form';
const Input = (props) => {
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.defaultValue}
render={({field: { onChange, onBlur, value, ref } }) => {
return <CInput defaultValue={props.defaultValue} id={props.id} onChange={onChange} />
}}
/>
)
}
export default Input;
问题是我的 console.log('fields are', fields)
一直告诉我 fields
是 []
。我不明白我在这里缺少什么。我正在将使用 useForm
设置的 control
传递给我的 <LineItems>
组件。
我的 defaultValues
对象的键名称与 useFieldArray
配置的 name
匹配,但字段始终显示为空。我希望有人可以让我知道我错过了什么。
谢谢!
显然我缺少 reset
函数。根据文档,需要重置,因为所有默认值都在第一次渲染时缓存。
我能够通过将以下内容添加到我的 TicketForm
组件来解决它:
useEffect(() => {
if (ticket)
reset({
line_items_attributes: [...ticket.line_items],
attachments_attributes: [...ticket.attachments],
})
}, [])
我是 React Hook Forms 的新手,除了在传入数据的编辑屏幕上使用 useFieldArray
显示 fields
之外,我一切正常。例如,我有以下:
TicketForm.js
import { useForm, useFieldArray, Controller } from 'react-hook-form';
import {
CCard,
CCardHeader,
CCollapse,
CCardBody,
CRow,
CCol,
CSidebar,
CSpinner,
CForm,
CFormGroup,
CInputCheckbox,
CFormText,
CTextarea,
CInput,
CInputFile,
CLabel,
CButton,
CButtonToolbar,
CButtonGroup,
CSelect
} from '@coreui/react';
import CIcon from '@coreui/icons-react';
import { useSelector } from 'react-redux';
import { useHistory } from 'react-router-dom';
import Input from '../../base/forms/input';
import Select from '../../base/forms/select';
import TextArea from '../../base/forms/text_area';
import Checkbox from '../../base/forms/check_box';
import LineItems from './line_items';
import Attachments from './attachment_items';
const TicketHookForm = props => {
let ticket = props.ticket;
const ticketData = Object.keys(ticket).length ? {
defaultValues: {
line_items_attributes: [...ticket.line_items],
attachments_attributes: [...ticket.attachments]
}
} : {};
console.log('ticket data is', ticketData);
const { setValue, control, handleSubmit, watch } = useForm(ticketData);
const stores = useSelector(state => state.referenceData.stores);
const categories = useSelector(state => state.referenceData.categories);
const history = useHistory();
const formatReferenceData = (data, selectedId) => {
return data.map(item => <option key={item.id} value={item.id} selected={item.id === selectedId}>{item.name}</option>);
}
const submit = (data) => {
console.log('data', data);
props.onSubmit(data);
}
return (
<CRow>
<CCol xs={12}>
<CForm onSubmit={(e) => {
e.preventDefault();
handleSubmit(submit)()
}} method="post" encType="multipart/form-data">
<CFormGroup row>
<CCol xs={3}>
<CLabel htmlFor="line_items">Line Items</CLabel>
</CCol>
<CCol xs={9}>
<LineItems control={control} />
</CCol>
</CFormGroup>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>Additional Information</CCardHeader>
<CCardBody>
<CFormGroup row>
<CCol xs={3}>
<CLabel htmlFor="attachments">Attachments</CLabel>
</CCol>
<CCol xs={9}>
<Attachments control={control} setValue={setValue} />
</CCol>
</CFormGroup>
</CCardBody>
</CCard>
<CCard>
<CCardHeader>
<CButton type="submit" color="primary"><CIcon name="cil-user" /> {props.ticketId ? 'Update' : 'Create'} Check Request</CButton>
<CButton type="reset" color="danger" onClick={() => history.goBack()}><CIcon name="cil-ban" /> Cancel</CButton>
</CCardHeader>
</CCard>
</CForm>
</CCol>
</CRow>
)
}
TicketHookForm.defaultProps = {
ticket: {}
}
export default TicketHookForm;
从上面的 console.log 中,我看到 ticketData
设置正确。例如,我有这个输出:
ticket data is {
defaultValues:
attachments_attributes: [{…}]
line_items_attributes: [{id: 8, description: "333", store: "Holman Cadillac", store_id: 2, account: "1", …}]
}
}
如果我注销 control
是什么,我也会注意到一切都是空的:
control is {
fieldArrayDefaultValuesRef: {
current: {
attachments_attributes: [],
line_items_attributes: []
}
}
然后,我有这个文件LineItems.js
import { useFieldArray } from 'react-hook-form';
import {
CFormGroup,
CRow,
CLabel,
CButton,
CCol
} from '@coreui/react';
import Input from '../../base/forms/input';
import Select from '../../base/forms/select';
import { useSelector } from 'react-redux';
const LineItems = props => {
const { fields, append, prepend, remove, swap, move, insert } = useFieldArray({
control: props.control,
name: 'line_items_attributes'
});
console.log('fields are ', fields);
const stores = useSelector(state => state.referenceData.stores);
const formatStores = () => {
return stores.map(item => <option key={item.id} value={item.id}>{item.name}</option>);
}
return (
<section className="line-item">
{fields.map((item, index) => (
<div key={item.id}>
<CFormGroup row>
<CCol xs={4}>
<CLabel htmlFor="store">Store</CLabel>
<Select control={props.control} defaultValue={item.store_id} id="store-select" name={`line_items_attributes[${index}].store_id`} options={formatStores(stores)} control={props.control} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="description">Description</CLabel>
<Input control={props.control} defaultValue={item.description} id="description" name={`line_items_attributes[${index}].description`} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="control_1">Control 1</CLabel>
<Input control={props.control} defaultValue={item.control} id="control_1" name={`line_items_attributes[${index}].control`} />
</CCol>
</CFormGroup>
<CFormGroup row>
<CCol xs={4}>
<CLabel htmlFor="account">Account</CLabel>
<Input control={props.control} defaultValue={item.account} name={`line_items_attributes[${index}].account`} id="account" />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="amount">Amount</CLabel>
<Input control={props.control} defaultValue={item.amount} type="number" id="amount" name={`line_items_attributes[${index}].amount`} />
</CCol>
<CCol xs={4}>
<CLabel htmlFor="control_2">Control 2</CLabel>
<Input control={props.control} defaultValue={item.control2} name={`line_items_attributes[${index}].control2`} id="control_2" />
</CCol>
</CFormGroup>
<CRow>
<CCol xs={12} className="text-right"><CButton color="danger" onClick={() => remove(index)}>Remove</CButton></CCol>
</CRow>
</div>
))}
<CButton color="primary" variant="outline" onClick={() => append({})}>Add Line</CButton>
</section>
)
}
export default LineItems;
Input.js
import {
CInput
} from '@coreui/react';
import { Controller } from 'react-hook-form';
const Input = (props) => {
return (
<Controller
control={props.control}
name={props.name}
defaultValue={props.defaultValue}
render={({field: { onChange, onBlur, value, ref } }) => {
return <CInput defaultValue={props.defaultValue} id={props.id} onChange={onChange} />
}}
/>
)
}
export default Input;
问题是我的 console.log('fields are', fields)
一直告诉我 fields
是 []
。我不明白我在这里缺少什么。我正在将使用 useForm
设置的 control
传递给我的 <LineItems>
组件。
我的 defaultValues
对象的键名称与 useFieldArray
配置的 name
匹配,但字段始终显示为空。我希望有人可以让我知道我错过了什么。
谢谢!
显然我缺少 reset
函数。根据文档,需要重置,因为所有默认值都在第一次渲染时缓存。
我能够通过将以下内容添加到我的 TicketForm
组件来解决它:
useEffect(() => {
if (ticket)
reset({
line_items_attributes: [...ticket.line_items],
attachments_attributes: [...ticket.attachments],
})
}, [])