Refactor NewObjectForm to Improve Default Values Handling
All checks were successful
farmcontrol/farmcontrol-ui/pipeline/head This commit looks good

- Introduced EMPTY_DEFAULT_VALUES constant to standardize default values.
- Added serializeDefaultValues function for safe serialization of default values.
- Updated NewObjectForm to use a ref for defaultValues, ensuring consistent access during form initialization and validation.
- Adjusted useEffect dependencies to reflect changes in default values handling.
This commit is contained in:
Tom Butcher 2026-11-08 20:47:47 +00:00
parent ab638e398e
commit 3544ac0d89

View File

@ -12,6 +12,16 @@ import {
calculateModelComputedEntries calculateModelComputedEntries
} from '../utils/Utils' } from '../utils/Utils'
const EMPTY_DEFAULT_VALUES = {}
const serializeDefaultValues = (value) => {
try {
return JSON.stringify(value ?? null)
} catch {
return null
}
}
const buildObjectFromEntries = (entries = []) => { const buildObjectFromEntries = (entries = []) => {
return entries.reduce((acc, entry) => { return entries.reduce((acc, entry) => {
const { namePath, value } = entry || {} const { namePath, value } = entry || {}
@ -53,13 +63,21 @@ const applyComputedEntries = (base, entries = []) => {
* loading, submitLoading, disabled, handleSubmit, form, formValid, objectData, setObjectData * loading, submitLoading, disabled, handleSubmit, form, formValid, objectData, setObjectData
* }) => ReactNode * }) => ReactNode
*/ */
const NewObjectForm = ({ type, style, defaultValues = {}, children }) => { const NewObjectForm = ({
type,
style,
defaultValues = EMPTY_DEFAULT_VALUES,
children
}) => {
// Do not initialise this from defaultValues. // Do not initialise this from defaultValues.
// The form initialisation effect below is the single source of truth, // The form initialisation effect below is the single source of truth,
// matching ObjectForm's fetched-object handling. // matching ObjectForm's fetched-object handling.
const [objectData, setObjectData] = useState({ const [objectData, setObjectData] = useState({
_isEditing: true _isEditing: true
}) })
const defaultValuesKey = serializeDefaultValues(defaultValues)
const defaultValuesRef = useRef(defaultValues)
defaultValuesRef.current = defaultValues
const [submitLoading, setSubmitLoading] = useState(false) const [submitLoading, setSubmitLoading] = useState(false)
const [formValid, setFormValid] = useState(false) const [formValid, setFormValid] = useState(false)
@ -132,7 +150,7 @@ const NewObjectForm = ({ type, style, defaultValues = {}, children }) => {
* is important for object-select fields. * is important for object-select fields.
*/ */
useEffect(() => { useEffect(() => {
const initialData = mergeFormData(defaultValues || {}) const initialData = mergeFormData(defaultValuesRef.current || {})
const computedEntries = calculateComputedValues(initialData, model) const computedEntries = calculateComputedValues(initialData, model)
@ -155,7 +173,7 @@ const NewObjectForm = ({ type, style, defaultValues = {}, children }) => {
setObjectData(nextObjectData) setObjectData(nextObjectData)
return validateForm() return validateForm()
}, [form, defaultValues, calculateComputedValues, model, validateForm]) }, [form, defaultValuesKey, calculateComputedValues, model, validateForm])
// Validate form on change // Validate form on change
useEffect(() => { useEffect(() => {