Skip to content

Commit

Permalink
Use useFormContext from react-hook-form
Browse files Browse the repository at this point in the history
Instead of passing form props down through components we now use
`useFormContext` that allows the context to be passed to nested
components without having to do so with props. This should help with
readability as we need to use the form context in deeply nested
components.
  • Loading branch information
jasalisbury committed Feb 11, 2021
1 parent c5b47a7 commit f10c73f
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 147 deletions.
34 changes: 19 additions & 15 deletions frontend/src/components/Navigator/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,44 +5,48 @@ import {
render, screen, waitFor, within,
} from '@testing-library/react';

import { useFormContext } from 'react-hook-form';
import Navigator from '../index';
import { NOT_STARTED } from '../constants';

// eslint-disable-next-line react/prop-types
const Input = ({ name }) => {
const { register } = useFormContext();
return (
<input
type="radio"
data-testid={name}
name={name}
ref={register}
/>
);
};

const pages = [
{
position: 1,
path: 'first',
label: 'first page',
review: false,
render: (hookForm) => (
<input
type="radio"
data-testid="first"
ref={hookForm.register}
name="first"
/>
render: () => (
<Input name="first" />
),
},
{
position: 2,
path: 'second',
label: 'second page',
review: false,
render: (hookForm) => (
<input
type="radio"
data-testid="second"
ref={hookForm.register}
name="second"
/>
render: () => (
<Input name="second" />
),
},
{
position: 3,
label: 'review page',
path: 'review',
review: true,
render: (hookForm, allComplete, formData, onSubmit) => (
render: (allComplete, formData, onSubmit) => (
<div>
<button type="button" data-testid="review" onClick={onSubmit}>Continue</button>
</div>
Expand Down
16 changes: 9 additions & 7 deletions frontend/src/components/Navigator/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
/* eslint-disable react/jsx-props-no-spreading */
/*
The navigator is a component used to show multiple form pages. It displays a stickied nav window
on the left hand side with each page of the form listed. Clicking on an item in the nav list will
Expand All @@ -6,7 +7,7 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import { useForm } from 'react-hook-form';
import { FormProvider, useForm } from 'react-hook-form';
import { Form, Button, Grid } from '@trussworks/react-uswds';
import useDeepCompareEffect from 'use-deep-compare-effect';
import useInterval from '@use-it/interval';
Expand Down Expand Up @@ -125,10 +126,10 @@ function Navigator({
/>
</Grid>
<Grid col={12} tablet={{ col: 6 }} desktop={{ col: 8 }}>
<div id="navigator-form">
{page.review
<FormProvider {...hookForm}>
<div id="navigator-form">
{page.review
&& page.render(
hookForm,
allComplete,
formData,
onFormSubmit,
Expand All @@ -137,7 +138,7 @@ function Navigator({
approvingManager,
reportId,
)}
{!page.review
{!page.review
&& (
<Container skipTopPadding>
<NavigatorHeader
Expand All @@ -147,12 +148,13 @@ function Navigator({
onSubmit={handleSubmit(onContinue)}
className="smart-hub--form-large"
>
{page.render(hookForm, additionalData, formData, reportId)}
{page.render(additionalData, formData, reportId)}
<Button type="submit" disabled={!isValid}>Continue</Button>
</Form>
</Container>
)}
</div>
</div>
</FormProvider>
</Grid>
</Grid>
);
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/pages/ActivityReport/Pages/ReviewSubmit.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@ import {
Alert, Accordion,
} from '@trussworks/react-uswds';
import { Helmet } from 'react-helmet';
import { useFormContext } from 'react-hook-form';

import Container from '../../../components/Container';
import SubmitterReviewPage from './SubmitterReviewPage';
import ApproverReviewPage from './ApproverReviewPage';
import './ReviewSubmit.css';

const ReviewSubmit = ({
hookForm,
allComplete,
onSubmit,
onReview,
Expand All @@ -20,7 +20,7 @@ const ReviewSubmit = ({
approvingManager,
initialData,
}) => {
const { handleSubmit, register, formState } = hookForm;
const { handleSubmit, register, formState } = useFormContext();
const { additionalNotes } = initialData;
const { isValid } = formState;
const valid = allComplete && isValid;
Expand Down Expand Up @@ -108,7 +108,6 @@ ReviewSubmit.propTypes = {
additionalNotes: PropTypes.string,
}).isRequired,
// eslint-disable-next-line react/forbid-prop-types
hookForm: PropTypes.object.isRequired,
reviewItems: PropTypes.arrayOf(
PropTypes.shape({
id: PropTypes.string.isRequired,
Expand Down
24 changes: 13 additions & 11 deletions frontend/src/pages/ActivityReport/Pages/__tests__/ReviewSubmit.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* eslint-disable react/jsx-props-no-spreading */
import '@testing-library/jest-dom';
import { render, screen, waitFor } from '@testing-library/react';
import React from 'react';
import userEvent from '@testing-library/user-event';
import { useForm } from 'react-hook-form';
import { FormProvider, useForm } from 'react-hook-form';

import ReviewSubmit from '../ReviewSubmit';

Expand All @@ -20,16 +21,17 @@ const RenderReview = ({
defaultValues: { ...initialData, approvingManagerId },
});
return (
<ReviewSubmit
allComplete={allComplete}
onSubmit={onSubmit}
reviewItems={[]}
approvers={approvers}
hookForm={hookForm}
initialData={initialData}
onReview={onReview}
approvingManager={approvingManager}
/>
<FormProvider {...hookForm}>
<ReviewSubmit
allComplete={allComplete}
onSubmit={onSubmit}
reviewItems={[]}
approvers={approvers}
initialData={initialData}
onReview={onReview}
approvingManager={approvingManager}
/>
</FormProvider>
);
};

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/* eslint-disable react/jsx-props-no-spreading */
import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import fetchMock from 'fetch-mock';
import React from 'react';
import { useForm } from 'react-hook-form';
import { FormProvider, useForm } from 'react-hook-form';
import join from 'url-join';

import goalsObjectives from '../goalsObjectives';
Expand All @@ -21,9 +22,9 @@ const RenderGoalsObjectives = ({
const activityRecipients = grantIds.map((id) => ({ activityRecipientId: id }));
const data = { ...initialData, activityRecipientType, activityRecipients };
return (
<>
{goalsObjectives.render(hookForm, {}, data)}
</>
<FormProvider {...hookForm}>
{goalsObjectives.render({}, data)}
</FormProvider>
);
};

Expand Down
29 changes: 9 additions & 20 deletions frontend/src/pages/ActivityReport/Pages/activitySummary.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import React, { useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
import { Helmet } from 'react-helmet';
import { useFormContext } from 'react-hook-form';

import {
Fieldset, Radio, Label, Grid, TextInput, Checkbox,
Expand All @@ -17,14 +18,16 @@ import {
} from '../constants';

const ActivitySummary = ({
register,
watch,
setValue,
control,
getValues,
recipients,
collaborators,
}) => {
const {
register,
watch,
setValue,
control,
getValues,
} = useFormContext();
const activityRecipientType = watch('activityRecipientType');
const startDate = watch('startDate');
const endDate = watch('endDate');
Expand Down Expand Up @@ -274,10 +277,6 @@ const ActivitySummary = ({
};

ActivitySummary.propTypes = {
register: PropTypes.func.isRequired,
watch: PropTypes.func.isRequired,
setValue: PropTypes.func.isRequired,
getValues: PropTypes.func.isRequired,
collaborators: PropTypes.arrayOf(
PropTypes.shape({
name: PropTypes.string.isRequired,
Expand All @@ -303,8 +302,6 @@ ActivitySummary.propTypes = {
}),
),
}).isRequired,
// eslint-disable-next-line react/forbid-prop-types
control: PropTypes.object.isRequired,
};

const sections = [
Expand Down Expand Up @@ -361,19 +358,11 @@ export default {
path: 'activity-summary',
sections,
review: false,
render: (hookForm, additionalData) => {
const {
register, watch, setValue, getValues, control,
} = hookForm;
render: (additionalData) => {
const { recipients, collaborators } = additionalData;
return (
<ActivitySummary
register={register}
watch={watch}
recipients={recipients}
setValue={setValue}
getValues={getValues}
control={control}
collaborators={collaborators}
/>
);
Expand Down
24 changes: 9 additions & 15 deletions frontend/src/pages/ActivityReport/Pages/goalsObjectives.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,20 @@ import {
Fieldset, Label, Textarea,
} from '@trussworks/react-uswds';
import useDeepCompareEffect from 'use-deep-compare-effect';
import { useFormContext } from 'react-hook-form';

import GoalPicker from './components/GoalPicker';
import { getGoals } from '../../../fetchers/activityReports';

const GoalsObjectives = ({
control, grantIds, register, watch, setValue, activityRecipientType,
grantIds, activityRecipientType,
}) => {
const {
control,
register,
watch,
setValue,
} = useFormContext();
const [availableGoals, updateAvailableGoals] = useState([]);
const [loading, updateLoading] = useState(true);
const goals = watch('goals');
Expand Down Expand Up @@ -62,12 +69,7 @@ const GoalsObjectives = ({
};

GoalsObjectives.propTypes = {
register: PropTypes.func.isRequired,
setValue: PropTypes.func.isRequired,
grantIds: PropTypes.arrayOf(PropTypes.number).isRequired,
watch: PropTypes.func.isRequired,
// eslint-disable-next-line react/forbid-prop-types
control: PropTypes.object.isRequired,
activityRecipientType: PropTypes.string.isRequired,
};

Expand All @@ -94,22 +96,14 @@ export default {
path: 'goals-objectives',
review: false,
sections,
render: (hookForm, additionalData, formData) => {
const {
register, watch, control, setValue,
} = hookForm;
render: (additionalData, formData) => {
const recipients = formData.activityRecipients || [];
const { activityRecipientType } = formData;
const grantIds = recipients.map((r) => r.activityRecipientId);
return (
<GoalsObjectives
activityRecipientType={activityRecipientType}
grantIds={grantIds}
formData={formData}
setValue={setValue}
watch={watch}
register={register}
control={control}
/>
);
},
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/pages/ActivityReport/Pages/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@ const reviewPage = {
path: 'review',
render:
(
hookForm,
allComplete,
formData,
onSubmit,
Expand All @@ -41,7 +40,6 @@ const reviewPage = {
allComplete={allComplete}
onSubmit={onSubmit}
onReview={onReview}
hookForm={hookForm}
approvingManager={approvingManager}
reviewItems={
pages.map((p) => reviewItem(p.path, p.label, p.sections, formData))
Expand Down
Loading

0 comments on commit f10c73f

Please sign in to comment.