Skip to content

Commit

Permalink
fix(core/presentation): Update useSaveRestore hook to store data for …
Browse files Browse the repository at this point in the history
…each key in a separate object
  • Loading branch information
christopherthielen authored and mergify[bot] committed May 6, 2020
1 parent 3156dff commit b75d371
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ function PizzaComponent() {
<FormikFormField name="topping" input={props => <SelectInput {...props} options={['peppers', 'mushrooms']} />} />
<FormikFormField name="crust" input={props => <SelectInput {...props} options={['thin', 'deepdish']} />} />
<FormikFormField name="sauce" input={props => <SelectInput {...props} options={['red', 'white']} />} />
<FormikFormField name="cheese" input={props => <SelectInput {...props} options={['mozzarella', 'cheddar']} />} />
</>
);
}
Expand All @@ -28,7 +29,7 @@ function SandwichComponent() {

function OrderComponent({ formik }: { formik: FormikProps<any> }) {
useSaveRestoreMutuallyExclusiveFields(formik, formik.values.pizzaOrSandwich, {
pizza: ['topping', 'crust', 'sauce'],
pizza: ['topping', 'crust', 'sauce', 'cheese'],
sandwich: ['bread', 'meat', 'cheese'],
});

Expand All @@ -52,6 +53,7 @@ const initialValues = {
topping: 'pepperoni',
crust: 'thin',
sauce: 'red',
cheese: 'cheddar',
};

const setupTest = (formikRef: React.MutableRefObject<any>) => {
Expand Down Expand Up @@ -92,6 +94,7 @@ describe('useSaveRestoreMutuallyExclusiveFields hook', () => {
topping: 'pepperoni',
crust: 'thin',
sauce: 'red',
cheese: 'cheddar',
});
});

Expand All @@ -115,6 +118,7 @@ describe('useSaveRestoreMutuallyExclusiveFields hook', () => {
topping: 'pepperoni',
crust: 'thin',
sauce: 'red',
cheese: 'cheddar',
});

formikRef.current.setFieldValue('pizzaOrSandwich', 'sandwich');
Expand All @@ -127,4 +131,28 @@ describe('useSaveRestoreMutuallyExclusiveFields hook', () => {
cheese: 'cheddar',
});
});

it(`saves and restores different values for keys that exist in multiple field sets`, () => {
const formikRef = React.createRef<Formik>();
const wrapper = setupTest(formikRef);

formikRef.current.setFieldValue('cheese', 'mozzarella');

formikRef.current.setFieldValue('pizzaOrSandwich', 'sandwich');
wrapper.setProps({});

formikRef.current.setFieldValue('bread', 'wheat');
formikRef.current.setFieldValue('meat', 'ham');
formikRef.current.setFieldValue('cheese', 'cheddar');

formikRef.current.setFieldValue('pizzaOrSandwich', 'pizza');
wrapper.setProps({});
// restored the pizza fields
expect(formikRef.current.getFormikBag().values.cheese).toEqual('mozzarella');

formikRef.current.setFieldValue('pizzaOrSandwich', 'sandwich');
wrapper.setProps({});
// restored the sandwich fields
expect(formikRef.current.getFormikBag().values.cheese).toEqual('cheddar');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ import { get } from 'lodash';
*
* Note: this hook does not explicitly attempt to manage default values for form fields
*
* @param formik formik props (typically from the Formik render function)
* @param currentFieldSetKey the current form mode (e.g., the value of the selected radio button)
* @param formik
* @param currentFieldSetKey the key for the current field (the form mode, e.g., the value of the selected radio button)
* @param mutuallyExclusiveFieldSets an object with:
* - keys: one for each form mode
* - values: lodash paths to the form fields exclusively owned by that form mode
* - keys: one for each mutually exclusive fieldset
* - values: lodash paths to the form fields exclusively owned by that fieldset
*
* Example:
*
Expand All @@ -35,35 +35,51 @@ import { get } from 'lodash';
* <FormikFormField name="toppings" input={props => <SelectInput {...props} options={toppingsOptions}>} />
* <FormikFormField name="crust" input={props => <SelectInput {...props} options={crustOptions}>} />
* <FormikFormField name="sauce" input={props => <SelectInput {...props} options={sauceOptions}>} />
* <FormikFormField name="cheese" input={props => <SelectInput {...props} options={pizzaCheeseOptions}>} />
* </>)}
*
* { formik.values.pizzaOrSandwich === 'sandwich' && (<>
* <FormikFormField name="bread" input={props => <SelectInput {...props} options={breadOptions}>} />
* <FormikFormField name="meat" input={props => <SelectInput {...props} options={meatOptions}>} />
* <FormikFormField name="cheese" input={props => <SelectInput {...props} options={cheeseOptions}>} />
* <FormikFormField name="cheese" input={props => <SelectInput {...props} options={sandwichCheeseOptions}>} />
* </>)}
*/
export function useSaveRestoreMutuallyExclusiveFields(
formik: FormikProps<any>,
currentFieldSetKey: string,
mutuallyExclusiveFieldSets: { [fieldSetId: string]: string[] },
mutuallyExclusiveFieldSets: { [fieldSetKey: string]: string[] },
) {
const previousFormMode = usePrevious(currentFieldSetKey);
const [savedData, setSavedData] = useState({} as { [path: string]: any });
interface SavedFieldsets {
[fieldSetKey: string]: FieldsetData;
}
interface FieldsetData {
[path: string]: any;
}

// Whenever the user switches the form mode source, clear out the
// previous form mode's exclusive field values and restore the new mode's values.
const previousFieldSetKey = usePrevious(currentFieldSetKey);
const [savedData, setSavedData] = useState<SavedFieldsets>({});

// Whenever the fieldset key changes, save and clear out the
// previous fieldset's values and restore the current fieldset's values.
useEffect(() => {
if (!!previousFormMode && currentFieldSetKey !== previousFormMode) {
const fieldsToSave = mutuallyExclusiveFieldSets[previousFormMode] ?? [];
if (!!previousFieldSetKey && currentFieldSetKey !== previousFieldSetKey) {
const fieldsToSave = mutuallyExclusiveFieldSets[previousFieldSetKey] ?? [];
const fieldsToRestore = mutuallyExclusiveFieldSets[currentFieldSetKey] ?? [];

const savedDataCopy = { ...savedData };
fieldsToSave.forEach(path => (savedDataCopy[path] = get(formik.values, path)));
setSavedData(savedDataCopy);
const dataToSave = fieldsToSave.reduce((data, path) => {
data[path] = get(formik.values, path);
return data;
}, {} as FieldsetData);
setSavedData({ ...savedData, [previousFieldSetKey]: dataToSave });

const dataToRestore = savedData[currentFieldSetKey] || {};

fieldsToSave.forEach(field => formik.setFieldValue(field, undefined));
fieldsToRestore.forEach(path => formik.setFieldValue(path, savedData[path]));
fieldsToRestore.forEach(path => {
if (dataToRestore.hasOwnProperty(path)) {
formik.setFieldValue(path, savedData[currentFieldSetKey][path]);
}
});
}
}, [currentFieldSetKey]);
}

0 comments on commit b75d371

Please sign in to comment.