factor out unnecessary temporary array

This commit is contained in:
Sampo Riitala
2024-11-13 03:21:11 +02:00
committed by Sampo
parent a35b6fce33
commit 0000511ec6
7 changed files with 31 additions and 34 deletions
+3 -3
View File
@@ -49,11 +49,11 @@ The context can also be used to access, for example, the **setEditData** setter,
**editingComponents**
If an editingComponent has an error, the `field` value of the component is added to the `allErrors` array in the context. editingComponents have a useEffect hook that runs every time their `error` value changes which either adds or removes them from the `allErrors` array. This array is used to make sure all fields have a proper value before allowing the user to add a new entry (the "Finalize Entry" button is disabled if `allErrors` has anything in it).
If an editingComponent has an error, the `field` value of the component is added to the `fieldsWithErrors` array in the context. editingComponents have a useEffect hook that runs every time their `error` value changes which either adds or removes them from the `fieldsWithErrors` array. This array is used to make sure all fields have a proper value before allowing the user to add a new entry (the "Finalize Entry" button is disabled if `fieldsWithErrors` has anything in it).
Instead of calling the `setAllErrors` function directly with the new array of errors, editingComponents pass an updater function to it.
Instead of calling the `setFieldsWithErrors` function directly with the new array of errors, editingComponents pass an updater function to it.
![setAllErrors](../images/set_all_errors.png)
![setFieldsWithErrors](../images/setFieldsWithErrors.png)
This ensures that when multiple components try to update the state at the same time, they don't overwrite each other. The react documentation goes into more detail: https://react.dev/reference/react/useState#updating-state-based-on-the-previous-state
Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

@@ -69,8 +69,8 @@ export type DetailContextType<T> = {
optionalRadioSelectionProps?: OptionalRadioSelectionProps
) => JSX.Element
validator: (editData: EditDataType<T>, field: keyof EditDataType<T>) => ValidationObject
allErrors: Array<string>
setAllErrors: (updaterFn: (prevErrors: Array<string>) => Array<string>) => void
fieldsWithErrors: Array<string>
setFieldsWithErrors: (updaterFn: (prevErrors: Array<string>) => Array<string>) => void
}
export const DetailContext = createContext<DetailContextType<unknown>>(null!)
@@ -73,7 +73,7 @@ export const DetailView = <T extends object>({
}
const { editRights } = usePageContext()
const [mode, setModeState] = useState<ModeType>(isNew ? modeOptionToMode['new'] : modeOptionToMode['read'])
const [allErrors, setAllErrors] = useState<Array<string>>([])
const [fieldsWithErrors, setFieldsWithErrors] = useState<Array<string>>([])
const [tab, setTab] = useState(getUrl())
useEffect(() => {
@@ -125,21 +125,18 @@ export const DetailView = <T extends object>({
radioSelection,
bigTextField,
validator,
allErrors,
setAllErrors,
fieldsWithErrors,
setFieldsWithErrors,
}
useEffect(() => {
if (mode.option === 'edit' || mode.option === 'new') {
const validationErrors: Array<string> = []
for (const field in initialState.editData) {
// if (field === 'references') continue
const { error } = validator(initialState.editData, field)
if (error) {
validationErrors.push(field)
setFieldsWithErrors(fieldsWithErrors => fieldsWithErrors.concat(field))
}
}
setAllErrors(validationErrors)
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [mode])
@@ -51,19 +51,19 @@ export const DropdownSelector = <T extends object>({
field: keyof EditDataType<T>
disabled?: boolean
}) => {
const { setEditData, editData, validator, allErrors, setAllErrors } = useDetailContext<T>()
const { setEditData, editData, validator, fieldsWithErrors, setFieldsWithErrors } = useDetailContext<T>()
const { error } = validator(editData, field)
useEffect(() => {
const errorField = String(field)
if (error && !allErrors.includes(errorField)) {
if (error && !fieldsWithErrors.includes(errorField)) {
// saves invalid field into array of errors in context
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return [...prevErrors, errorField]
})
} else if (!error && allErrors.includes(errorField)) {
} else if (!error && fieldsWithErrors.includes(errorField)) {
// removes valid field from the array
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return prevErrors.filter(err => err !== errorField)
})
}
@@ -227,20 +227,20 @@ export const EditableTextField = <T extends object>({
readonly?: boolean
handleSetEditData?: (value: number | string) => void
}) => {
const { setEditData, editData, validator, allErrors, setAllErrors } = useDetailContext<T>()
const { setEditData, editData, validator, fieldsWithErrors, setFieldsWithErrors } = useDetailContext<T>()
const { error } = validator(editData, field)
const name = String(field)
useEffect(() => {
const errorField = String(field)
if (error && !allErrors.includes(errorField)) {
if (error && !fieldsWithErrors.includes(errorField)) {
// saves invalid field into array of errors in context
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return [...prevErrors, errorField]
})
} else if (!error && allErrors.includes(errorField)) {
} else if (!error && fieldsWithErrors.includes(errorField)) {
// removes valid field from the array
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return prevErrors.filter(err => err !== errorField)
})
}
@@ -294,7 +294,7 @@ export const FieldWithTableSelection = <T extends object, ParentType extends obj
selectorTable: ReactElement
disabled?: boolean
}) => {
const { editData, setEditData, validator, allErrors, setAllErrors } = useDetailContext<ParentType>()
const { editData, setEditData, validator, fieldsWithErrors, setFieldsWithErrors } = useDetailContext<ParentType>()
const { error } = validator(editData, targetField as keyof EditDataType<ParentType>)
const [open, setOpen] = useState(false)
const selectorFn = (selected: T) => {
@@ -304,14 +304,14 @@ export const FieldWithTableSelection = <T extends object, ParentType extends obj
useEffect(() => {
const errorField = String(targetField)
if (error && !allErrors.includes(errorField)) {
if (error && !fieldsWithErrors.includes(errorField)) {
// saves invalid field into array of errors in context
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return [...prevErrors, errorField]
})
} else if (!error && allErrors.includes(errorField)) {
} else if (!error && fieldsWithErrors.includes(errorField)) {
// removes valid field from the array
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return prevErrors.filter(err => err !== errorField)
})
}
@@ -363,7 +363,7 @@ export const TimeBoundSelection = <T extends object, ParentType extends object>(
selectorTable: ReactElement
disabled?: boolean
}) => {
const { editData, setEditData, validator, allErrors, setAllErrors } = useDetailContext<ParentType>()
const { editData, setEditData, validator, fieldsWithErrors, setFieldsWithErrors } = useDetailContext<ParentType>()
const { error: boundError } = validator(
editData,
(targetField === 'up_bnd' ? 'up_bound' : 'low_bound') as keyof EditDataType<ParentType>
@@ -381,14 +381,14 @@ export const TimeBoundSelection = <T extends object, ParentType extends object>(
useEffect(() => {
const errorField = String(targetField)
if (boundError && !allErrors.includes(errorField)) {
if (boundError && !fieldsWithErrors.includes(errorField)) {
// saves invalid field into array of errors in context
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return [...prevErrors, errorField]
})
} else if (!boundError && allErrors.includes(errorField)) {
} else if (!boundError && fieldsWithErrors.includes(errorField)) {
// removes valid field from the array
setAllErrors(prevErrors => {
setFieldsWithErrors(prevErrors => {
return prevErrors.filter(err => err !== errorField)
})
}
@@ -14,7 +14,7 @@ export const WriteButton = <T,>({
onWrite: (editData: EditDataType<T>, setEditData: (editData: EditDataType<T>) => void) => Promise<void>
hasStagingMode?: boolean
}) => {
const { editData, setEditData, mode, setMode, allErrors } = useDetailContext<T>()
const { editData, setEditData, mode, setMode, fieldsWithErrors } = useDetailContext<T>()
const [loading, setLoading] = useState(false)
const getButtonText = () => {
@@ -24,7 +24,7 @@ export const WriteButton = <T,>({
return (
<Button
disabled={allErrors.length > 0}
disabled={fieldsWithErrors.length > 0}
id="write-button"
sx={{ width: '20em' }}
onClick={() => {