Skip to main content

Form submission

When it's time to submit the form, it is handy to have a custom hook that handles all the logic behind submission. This can help keeping the component clean by abstracting the logic away, especially when calling multiple services or doing a lot when submitting the form

1. Create a custom hook#

This should handle everything that needs to happen when subbmitting the form including calling mutation services or redirecting the user back to overview page etc

components/organization-units/details/hooks/useCompanyInfoSubmit.ts
export const useCompanyInfoSubmit = () => {  const intl = useIntl();  const { addNotification } = useContext(NotificationsContext);
  // Service mutation handlers  const { updateOrganizationUnit, isUpdateOULoading } = useUpdateOrganizationUnit();  const { updateOrganizationUnitSettings, isUpdateOUSettingsLoading } =    useUpdateOrganizationUnitSettings();  const { updateOrganizationUnitNotes, isUpdateOUNotesLoading } = useUpdateOrganizationUnitNotes();
  // Other logic that we need to do when submitting the form  const setCurrentEditingCardTab = useSetRecoilState(basicInformationTabCardBeingEdited);
  // This is the submit handler that will be called when the form is submitted.  const handleSubmit = useCallback(    (basicInfoValues: IBasicInformationDetails) => {      if (basicInfoValues.ID) {        const promises = [          updateOrganizationUnit({            ID: basicInfoValues.ID,            Name: basicInfoValues.Name,            RegistrationNumber: basicInfoValues.RegistrationNumber,            VatNumber: basicInfoValues.VatNumber,            BankAccount: basicInfoValues.BankAccount,          }),          updateOrganizationUnitSettings({            ID: basicInfoValues.ID,            AssortmentID: basicInfoValues.AssortmentID,          }),          updateOrganizationUnitNotes({            OrganizationUnitID: basicInfoValues.ID,            Notes: basicInfoValues.Notes ?? '',          }),        ];
        Promise.all(promises).then((responses) => {          if (responses.every((response) => !isNil(response))) {            setCurrentEditingCardTab(undefined);            addNotification({              message: intl.formatMessage({                id: 'organizations.details.tabs.basic-info.company-info.success.message',              }),              showIcon: true,              iconType: 'success',            });          }        });      }    },    [      addNotification,      intl,      setCurrentEditingCardTab,      updateOrganizationUnit,      updateOrganizationUnitNotes,      updateOrganizationUnitSettings,    ],  );
  // State that keeps track of when the action is already in progress  const isUpdateInProgress = useMemo(    () => isUpdateOULoading || isUpdateOUSettingsLoading || isUpdateOUNotesLoading,    [isUpdateOULoading, isUpdateOUNotesLoading, isUpdateOUSettingsLoading],  );
  return { handleSubmit, isUpdateInProgress };};

We usually return a loading state alongside the submit handler that the component can use to show a progress bar and disable the submit button when the there's already a create/update action in progress.

2. Use the custom hook in the form component#

Call the submit handler from the custom hook in your form component.

components/organization-units/details/CompanyInfoCard.tsx
const CompanyInfoCard = () => {  ...
  const initialValues = useMemo<IBasicInformationDetails>(    () => ({      ID: organizationUnitDetailsResponse?.ID,      Name: organizationUnitDetailsResponse?.Name,      RegistrationNumber: organizationUnitDetailsResponse?.RegistrationNumber,      VatNumber: organizationUnitDetailsResponse?.VatNumber,      BankAccount: organizationUnitDetailsResponse?.BankAccount,      AssortmentID: organizationUnitSettingsResponse?.AssortmentID,      AssortmentName: organizationUnitSettingsResponse?.AssortmentName,      Notes: organizationUnitNotesResponse?.Notes,    }),    [      organizationUnitDetailsResponse?.BankAccount,      organizationUnitDetailsResponse?.ID,      organizationUnitDetailsResponse?.Name,      organizationUnitDetailsResponse?.RegistrationNumber,      organizationUnitDetailsResponse?.VatNumber,      organizationUnitNotesResponse?.Notes,      organizationUnitSettingsResponse?.AssortmentID,      organizationUnitSettingsResponse?.AssortmentName,    ],  );
  const validationSchema = useCompanyInfoValidationSchema();
  const { handleSubmit, isUpdateInProgress } = useCompanyInfoSubmit();
  return (    <RelativeBox>      <ProgressBar position="top" loading={isUpdateInProgress} />      <Card inner>        <Formik          initialValues={initialValues}          enableReinitialize          validationSchema={validationSchema}          onSubmit={(values, formikHelpers) => {            handleSubmit(values);            formikHelpers.setSubmitting(false);          }}        >          {({ setFieldValue }) => (            <>            <EditableCardHeader                title={intl.formatMessage({                  id: 'organizations.details.tabs.basic-info.company-info.title',                })}                editModeTitle={intl.formatMessage({                  id: 'organizations.details.tabs.basic-info.company-info.edit-mode.title',                })}                tabCard={BasicInformationTabCard.CompanyInfo}                isEditModeState={basicInformationTabCardBeingEdited}                isActionsDisabled={isUpdateInProgress}                isCurrentlyEditingTabCardSelector={isCurrentlyEditingBasicInformationTabCard(                  BasicInformationTabCard.CompanyInfo,                )}              />              ...            </>          )}        </Formik>      </Card>    </RelativeBox>  );};