Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Expose formikbag as imperative methods #1972

Merged
merged 3 commits into from
Jan 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
71 changes: 38 additions & 33 deletions packages/formik/src/Formik.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -328,21 +328,21 @@ export function useFormik<Values extends FormikValues = FormikValues>({
(values: Values = state.values) => {
return unstable_runWithPriority(LowPriority, () => {
return runAllValidations(values)
.then(combinedErrors => {
if (!!isMounted.current) {
dispatch({ type: 'SET_ERRORS', payload: combinedErrors });
}
return combinedErrors;
})
.catch(actualException => {
if (process.env.NODE_ENV !== 'production') {
// Users can throw during validate, however they have no way of handling their error on touch / blur. In low priority, we need to handle it
console.warn(
`Warning: An unhandled error was caught during low priority validation in <Formik validate />`,
actualException
);
}
});
.then(combinedErrors => {
if (!!isMounted.current) {
dispatch({ type: 'SET_ERRORS', payload: combinedErrors });
}
return combinedErrors;
})
.catch(actualException => {
if (process.env.NODE_ENV !== 'production') {
// Users can throw during validate, however they have no way of handling their error on touch / blur. In low priority, we need to handle it
console.warn(
`Warning: An unhandled error was caught during low priority validation in <Formik validate />`,
actualException
);
}
});
});
}
);
Expand Down Expand Up @@ -652,7 +652,7 @@ export function useFormik<Values extends FormikValues = FormikValues>({
} else {
executeChange(eventOrPath);
}
},
}
);

const setFieldTouched = useEventCallback(
Expand Down Expand Up @@ -693,15 +693,15 @@ export function useFormik<Values extends FormikValues = FormikValues>({
[setFieldTouched]
);

const handleBlur = useEventCallback(
(eventOrString: any): void | ((e: any) => void) => {
if (isString(eventOrString)) {
return event => executeBlur(event, eventOrString);
} else {
executeBlur(eventOrString);
}
},
);
const handleBlur = useEventCallback((eventOrString: any):
| void
| ((e: any) => void) => {
if (isString(eventOrString)) {
return event => executeBlur(event, eventOrString);
} else {
executeBlur(eventOrString);
}
});

const setFormikState = React.useCallback(
(
Expand Down Expand Up @@ -988,7 +988,11 @@ export function Formik<
ExtraProps = {}
>(props: FormikConfig<Values> & ExtraProps) {
const formikbag = useFormik<Values>(props);
const { component, children, render } = props;
const { component, children, render, innerRef } = props;

// This allows folks to pass a ref to <Formik />
React.useImperativeHandle(innerRef, () => formikbag);

React.useEffect(() => {
if (__DEV__) {
invariant(
Expand Down Expand Up @@ -1138,9 +1142,9 @@ function getValueForCheckbox(
}

// If the currentValue was not a boolean we want to return an array
let currentArrayOfValues = []
let isValueInArray = false
let index = -1
let currentArrayOfValues = [];
let isValueInArray = false;
let index = -1;

if (!Array.isArray(currentValue)) {
// eslint-disable-next-line eqeqeq
Expand All @@ -1149,24 +1153,25 @@ function getValueForCheckbox(
}
} else {
// If the current value is already an array, use it
currentArrayOfValues = currentValue
currentArrayOfValues = currentValue;
index = currentValue.indexOf(valueProp);
isValueInArray = index >= 0;
}


// If the checkbox was checked and the value is not already present in the aray we want to add the new value to the array of values
if (checked && valueProp && !isValueInArray) {
return currentArrayOfValues.concat(valueProp);
}

// If the checkbox was unchecked and the value is not in the array, simply return the already existing array of values
if (!isValueInArray) {
return currentArrayOfValues
return currentArrayOfValues;
}

// If the checkbox was unchecked and the value is in the array, remove the value and return the array
return currentArrayOfValues.slice(0, index).concat(currentArrayOfValues.slice(index + 1));
return currentArrayOfValues
.slice(0, index)
.concat(currentArrayOfValues.slice(index + 1));
}

// React currently throws a warning when using useLayoutEffect on the server.
Expand Down
3 changes: 3 additions & 0 deletions packages/formik/src/types.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,9 @@ export interface FormikConfig<Values> extends FormikSharedConfig {
* throws an error object where that object keys map to corresponding value.
*/
validate?: (values: Values) => void | object | Promise<FormikErrors<Values>>;

/** Inner ref */
innerRef?: (instance: any) => void;
}

/**
Expand Down
8 changes: 8 additions & 0 deletions packages/formik/test/Formik.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1288,4 +1288,12 @@ describe('<Formik>', () => {
getProps().validateForm();
}).toThrow('broken validations');
});

it('exposes formikbag as imperative methods', () => {
const innerRef: any = React.createRef();

const { getProps } = renderFormik({ innerRef });

expect(innerRef.current).toEqual(getProps());
});
});