Edit: I have been trying to implement a similar fix as this in my code, but I am very confused about how this method would translate in my code. I have been trying to apply that fix to my updateDose
function, but it isn't working.
I am creating an app using React, Material UI, React Hook Form, and Yup.
I have two dialogs, one for the "edit dose" button and the "delete med" button for each card. On the "edit dose" dialog, the user inputs a new dose into a form.
I am getting the following warning if I try to update a medication's dose more than once (the first update shows no error, and then the second shows this)...
Warning: Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in a useEffect cleanup function.
I have searched other tutorials to try to find a fix based on other examples, but I am not having any luck. Thank you so much in advance and here's my relevant code...
const Medication = ({medication}) => {
const {handleSubmit, control, formState} = useForm({
mode: "onChange",
resolver: yupResolver(validationSchema)
});
// This handles the update medication dialog
const [openUpdate, setOpenUpdate] = useState(false);
const handleClickOpenUpdate = () => {
setOpenUpdate(true);
};
const handleCloseUpdate = () => {
setOpenUpdate(false);
};
// Function for the update dose button
function updateDose(medicationId, parsedMedications, data) {
let medication;
let index;
for (let i = 0; i < parsedMedications.length; i++) {
if (parsedMedications[i].id === medicationId) {
medication = parsedMedications[i];
index = i;
}
}
medication.dose = data.dose;
parsedMedications[index] = medication;
localStorage.setItem("medications", JSON.stringify(parsedMedications));
// This forces the dialog to close
setOpenUpdate(false);
}
return (
<Box>
<Card sx={cardSx}>
<CardContent>
<Typography sx={typographyMedicationSx} variant="h5">
Medication: {medication.medication}
</Typography>
<Typography sx={typographyMedicationSx} variant="h5">
Dose: {medication.dose} mg
</Typography>
</CardContent>
<Box>
<Button onClick={() => handleClickOpenUpdate()} size="large"
sx={buttonSx}
variant="contained">Edit
Dose</Button>
<Button onClick={() => handleClickOpen()} color="error"
size="large"
sx={buttonSx} variant="contained">Delete
Med </Button>
</Box>
</Card>
{/* Update medication dialog */}
<Dialog
open={openUpdate}
onClose={handleCloseUpdate}
TransitionComponent={Transition}
>
<DialogTitle sx={dialogTitleSx}>
{handleCloseUpdate ? (
<IconButton
aria-label="close"
onClick={handleCloseUpdate}
sx={iconButtonSx}
>
<CloseIcon/>
</IconButton>
) : null}
</DialogTitle>
<form
onSubmit={handleSubmit((data) => updateDose(medication.id, parsed, data))}
noValidate>
<Typography sx={updateDoseTypographySx} variant="h4">
Update dose
</Typography>
<Box
sx={boxSx}
>
<Controller
name="dose"
control={control}
defaultValue={""}
render={({field: {ref, ...field}, fieldState: {error}}) => (
<Autocomplete
{...field}
autoHighlight
disableClearable
isOptionEqualToValue={(option, value) => option.id === value.id}
id="dose-autocomplete"
onChange={(event, value) => field.onChange(value.label)}
options={doseSuggestions}
renderInput={(params) => (
<TextField
required
error={!!error}
helperText={error?.message}
id="dose"
label="Dose"
name="dose"
type="numeric"
inputRef={ref}
{...params}
/>
)}
/>
)}
/>
<Button disabled={!formState.isValid} size="large"
sx={formButtonSx} type="submit"
variant="contained">Submit</Button>
</Box>
</form>
</Dialog>
</Box>
)
};
const medications = parsed.map((medication, index) => {
return (<Medication medication={medication} key={"medication" + index}/>)
});
Someone on a slack community helped me figure it out! I needed to add this to the dialog... keepMounted={true}