UNPKG

@imtf/rjsf-conditionals

Version:

Extension of @rjsf/core with conditional field support

83 lines (74 loc) 2.76 kB
import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import rulesRunner from "./rulesRunner"; import { deepEquals } from "@rjsf/utils"; import { unwrapFormData, wrapFormData } from "./utils"; /** * Usage: * const { schema, uiSchema } = useFormWithConditionnals(formData, schema, uiSchema, rules, onDataChange, Engine, extraActions) * return { schema, uiSchema } * @param formData * @param schema * @param uiSchema * @param rules * @param handleChange * @param Engine * @param [extraActions] * @return <object> */ const useFormWithConditionnals = function (formData, schema, uiSchema, rules, handleChange, Engine) { let extraActions = arguments.length > 6 && arguments[6] !== undefined ? arguments[6] : {}; // Default schema and uiSchema to undefined when falsy schema = schema || undefined; uiSchema = uiSchema || undefined; // Create the rules runner const runRules = useMemo(() => rulesRunner(schema, uiSchema, rules, Engine, extraActions), [Engine, extraActions, rules, schema, uiSchema]); // Keep a ref of the last run data const lastRunFormData = useRef(); // Keep a ref of current formData so we avoid redefining updateState const currentFormData = useRef(); currentFormData.current = formData; // Schemas will be defined by the rules const [state, setState] = useState({ schema: {}, uiSchema: {} }); const updateState = useCallback(_ref => { let { formData: nextFormData, ...nextSchemas } = _ref; return setState(state => { const unwrappedNextFormData = unwrapFormData(nextFormData); // Did the rules made some changes to the data? const dataChangedByRules = !deepEquals(unwrappedNextFormData, currentFormData.current); // trigger onChange only if data changed because of the rules if (dataChangedByRules) { handleChange?.({ formData: unwrappedNextFormData }); } const schemasChanged = !deepEquals({ schema: state.schema, uiSchema: state.uiSchema }, nextSchemas); if (schemasChanged) { return nextSchemas; } // If the schemas didn't change, we don't need to update the state return state; }); }, [handleChange]); useEffect(() => { // Did data changes from last run ? const dataChanged = !deepEquals(lastRunFormData.current, formData); if (dataChanged) { // First wrap the formData to prefix field names with entity const wrappedData = wrapFormData(formData); runRules(wrappedData).then(updateState); // Update lastRunFormData reference lastRunFormData.current = formData; } }, [formData, runRules, updateState]); return state; }; export default useFormWithConditionnals;