During development Eslint prompted me with this information:
The 'fields' object makes the dependencies of useCallback Hook (at line 183) change on every render. Move it inside the useCallback callback. Alternatively, wrap the initialization of 'fields' in its own useMemo() Hook
Code looks like this:
const fields: { [p: string]: EntityField } = {
'Kredieten': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.kredieten.id), [metadataService]),
'Deelnemingen': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.deelnemingen.id), [metadataService]),
'Toeleveranciers': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.toeleveranciers.id), [metadataService]),
'Vervoersmiddelen': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.vervoersmiddelen.id), [metadataService]),
'Liquide middelen': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.liquideMiddelen.id), [metadataService]),
'Voorraden': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.voorraden.id), [metadataService]),
'Groepsvermogen': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.groepsvermogen.id), [metadataService]),
'Gebouwen en terreinen': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.gebouwenEnTerreinen.id), [metadataService]),
'Machines & Installaties': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.machinesAndInstallaties.id), [metadataService]),
'Inventaris': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.inventaris.id), [metadataService]),
'Effecten': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.effecten.id), [metadataService]),
'Rechten & Vergunningen': useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.rechtenAndVergunningen.id), [metadataService]),
};
And the handle save:
const handleSave = useCallback(async () =>
{
setLoading(true);
Object.keys(data).forEach((x: string) => {
mutationHandler.updateEntityWithProperty(
dossier.entity,
new FieldProperty(fields[x]),
DataObjectValue.create(
new DataObject(
fields[x].specification,
{boolean: data[x]},
)
),
);
})
try
{
await mutationHandler.commit();
setLoading(false);
enqueueSnackbar('Succesvol opgeslagen');
}
catch (e)
{
showError(e, 'Opslaan mislukt');
setLoading(false);
}
}, [data, mutationHandler, dossier.entity, fields, enqueueSnackbar, showError]);
What did I miss, that whenever I want to wrap the fields in a useMemo:
const fields: { [p: string]: EntityField } = useMemo(() => ({
Eslint is screaming about useComputed?
Forgot to mention, this code is partly responsible for check boxes.
CodePudding user response:
React hooks can't be called from nested functions, i.e. the useCallback
or useMemo
callback functions.
Make all the useComputed
calls on their own first, then memoize the fields
object.
Example:
const Kredieten = useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.kredieten.id), [metadataService]);
const Deelnemingen = useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.deelnemingen.id), [metadataService]);
...
...
const RechtenVergunningen = useComputed(() => metadataService.getEntityField(RisicoAdviesDossier.PROPS.rechtenAndVergunningen.id), [metadataService]);
...
const fields: { [p: string]: EntityField } = useMemo(() => ({
Kredieten,
Deelnemingen,
...
...
'Rechten & Vergunningen': RechtenVergunningen,
}), [Kredieten, Deelnemingen, ..., RechtenVergunningen]);