Optimize reference update tracking by sourcing from direct modifications rather than state diff comparisons.

This commit is contained in:
arpitnath 2024-04-04 20:54:13 +05:30
parent 1c4c272c9f
commit d4e9f45ae2
6 changed files with 95 additions and 39 deletions

View file

@ -243,10 +243,10 @@ export const resolveReferences = (query, validationSchema, customResolvers = {},
if (fxActive && (value.startsWith('#') || value.includes('table-'))) {
value = JSON.stringify(value);
}
const { toResolveReference, jsExpression, jsExpMatch } = inferJSExpAndReferences(value, lookupTable.hints);
const isComponentValue = toResolveReference?.startsWith('components.') || false; //!Notes: As we removed the updating of references on currentState changes, exposed variable of components are dynamic and cannot be controlled in any form, so we are resolving only components references with our legacy approach.
if (!isComponentValue && !jsExpMatch && toResolveReference && lookupTable.hints.has(toResolveReference)) {
// const isComponentValue = toResolveReference?.startsWith('components.') || false; //!Notes: As we removed the updating of references on currentState changes, exposed variable of components are dynamic and cannot be controlled in any form, so we are resolving only components references with our legacy approach.
if (!jsExpMatch && toResolveReference && lookupTable.hints.has(toResolveReference)) {
const idToLookUp = lookupTable.hints.get(toResolveReference);
resolvedValue = lookupTable.resolvedRefs.get(idToLookUp);

View file

@ -326,47 +326,19 @@ const EditorComponent = (props) => {
flushComponentsToRender(updatedComponentIds);
}
const lastUpdatedRef = useResolveStore((state) => state.lastUpdatedRefs, shallow);
useEffect(() => {
const isEditorReady = useCurrentStateStore.getState().isEditorReady;
if (!isEditorReady || !onAppLoadAndPageLoadEventsAreTriggered.current) return;
const diffState = diff(prevCurrentStateRef.current, currentState);
if (Object.keys(diffState).length > 0) {
const entitiesToTrack = ['queries', 'components', 'variables', 'page', 'constants'];
const entitiesChanged = Object.keys(diffState).filter((entity) => entitiesToTrack.includes(entity));
if (entitiesChanged.length === 0) return;
const diffObj = entitiesChanged.reduce((acc, entity) => {
acc[entity] = diffState[entity];
return acc;
}, {});
const allPaths = entitiesChanged.reduce((acc, entity) => {
const paths = Object.keys(diffObj[entity]).map((key) => {
return generatePath(diffObj[entity], key);
});
acc[entity] = paths.map((path) => `${entity}.${path}`);
return acc;
}, {});
const currentStatePaths = Object.values(allPaths).flat();
if (lastUpdatedRef.length > 0) {
const currentComponents = useEditorStore.getState().appDefinition?.pages?.[currentPageId]?.components || {};
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, currentStatePaths);
const componentIdsWithReferences = findComponentsWithReferences(currentComponents, lastUpdatedRef);
if (componentIdsWithReferences.length > 0) {
batchUpdateComponents(componentIdsWithReferences);
}
prevCurrentStateRef.current = JSON.parse(JSON.stringify(currentState));
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [JSON.stringify(currentState)]);
}, [lastUpdatedRef]);
useEffect(
() => {
@ -1175,7 +1147,6 @@ const EditorComponent = (props) => {
});
useResolveStore.getState().actions.addEntitiesToMap(componentEntityArray);
useResolveStore.getState().actions.addAppSuggestions({
components: newComponentsExposedData,
});

View file

@ -37,6 +37,7 @@ import { useAppDataStore } from '@/_stores/appDataStore';
import { useEditorStore } from '@/_stores/editorStore';
import { useGridStore } from '@/_stores/gridStore';
import { useResolveStore } from '@/_stores/resolverStore';
import { handleLowPriorityWork } from './editorHelpers';
const ERROR_TYPES = Object.freeze({
ReferenceError: 'ReferenceError',
@ -115,11 +116,31 @@ export function onComponentOptionChanged(component, option_name, value) {
let componentData = components[componentName] || {};
componentData[option_name] = value;
const path = option_name ? `components.${componentName}.${option_name}` : null;
if (isEditorReady) {
// Always update the current state if editor is ready
useCurrentStateStore.getState().actions.setCurrentState({
components: { ...components, [componentName]: componentData },
});
if (!_.isEmpty(useResolveStore.getState().lookupTable?.resolvedRefs) && path) {
const lookUpTable = useResolveStore.getState().lookupTable;
const existingRef = lookUpTable.resolvedRefs?.get(lookUpTable.hints?.get(path));
if (typeof existingRef === 'function') return;
const shouldUpdateRef = existingRef !== componentData[option_name];
if (shouldUpdateRef) {
handleLowPriorityWork(() => {
useResolveStore
.getState()
.actions.updateResolvedRefsOfHints([{ hint: path, newRef: componentData[option_name] }]);
});
}
}
} else {
// Update the duplicate state if editor is not ready
duplicateCurrentState = { ...components, [componentName]: componentData };
@ -1091,6 +1112,14 @@ export function runQuery(
},
errors: {},
});
useResolveStore.getState().actions.addAppSuggestions({
queries: {
[queryName]: {
data: [],
isLoading: true,
},
},
});
}
let queryExecutionPromise = null;
if (query.kind === 'runjs') {
@ -1267,9 +1296,15 @@ export function runQuery(
queries: {
[queryName]: {
data: finalData,
isLoading: false,
},
},
});
const basePath = `queries.${queryName}`;
useResolveStore.getState().actions.updateLastUpdatedRefs([`${basePath}.data`, `${basePath}.isLoading`]);
resolve({ status: 'ok', data: finalData });
onEvent(_self, 'onDataQuerySuccess', queryEvents, mode);
}

View file

@ -1,6 +1,7 @@
import _ from 'lodash';
import { create } from './utils';
import { v4 as uuid } from 'uuid';
import { useResolveStore } from './resolverStore';
const STORE_NAME = 'Editor';
export const EMPTY_ARRAY = [];
@ -117,4 +118,5 @@ export const flushComponentsToRender = (componentIds = []) => {
if (!componentIds.length) return;
useEditorStore.getState().actions.flushComponentsNeedsUpdateOnNextRender(componentIds);
useResolveStore.getState().actions.getLastUpdatedRefs();
};

View file

@ -58,7 +58,7 @@ const initialState = {
hints: {},
resolvedRefs: {},
},
lastUpdatedRefs: [],
referenceMapper: new ReferencesBiMap(),
};
@ -78,6 +78,16 @@ export const useResolveStore = create(
}));
},
flushLastUpdatedRefs: () => {
set(() => ({ lastUpdatedRefs: [] }));
},
getLastUpdatedRefs: () => {
return get().lastUpdatedRefs;
},
//for queries references used in component definitons
updateLastUpdatedRefs: (updatedRefs) => {
set(() => ({ lastUpdatedRefs: updatedRefs }));
},
addAppSuggestions: (partialRefState) => {
if (Object.keys(partialRefState).length === 0) return;
@ -86,6 +96,8 @@ export const useResolveStore = create(
const lookupHintsMap = new Map([...get().lookupTable.hints]);
const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]);
const newUpdatedrefs = [];
hintsMap.forEach((value, key) => {
const alreadyExists = lookupHintsMap.has(key);
@ -97,6 +109,7 @@ export const useResolveStore = create(
resolvedRefs.delete(value);
resolvedRefs.set(existingLookupId, newResolvedRef);
newUpdatedrefs.push(key);
}
});
@ -118,6 +131,7 @@ export const useResolveStore = create(
hints: lookupHintsMap,
resolvedRefs: lookupResolvedRefs,
},
lastUpdatedRefs: newUpdatedrefs,
}));
},
@ -158,6 +172,35 @@ export const useResolveStore = create(
});
},
updateResolvedRefsOfHints: (resolvedRefs = []) => {
const lookupResolvedRefs = new Map([...get().lookupTable.resolvedRefs]);
const hintsMap = new Map([...get().lookupTable.hints]);
const updatedList = [];
resolvedRefs.forEach((ref) => {
if (!ref.hint || !ref.newRef || !hintsMap.has(ref.hint)) return;
const refId = hintsMap.get(ref.hint);
const currentRef = lookupResolvedRefs.get(refId);
if (currentRef !== ref.newRef) {
lookupResolvedRefs.set(refId, ref.newRef);
updatedList.push(ref.hint);
}
});
if (updatedList.length > 0) {
set(() => ({
lookupTable: {
...get().lookupTable,
resolvedRefs: lookupResolvedRefs,
},
lastUpdatedRefs: updatedList,
}));
}
},
updateJSHints: () => {
const hints = createJavaScriptSuggestions();
set(() => ({ suggestions: { ...get().suggestions, jsHints: hints } }));

View file

@ -465,7 +465,12 @@ export function createReferencesLookup(refState, forQueryParams = false, initalL
}
if (_type === 'Array') {
map.set(newPath, { type: _type });
buildMap(value, newPath);
if (path.startsWith('queries') && key === 'data' && value.length > 2) {
// do nothing
} else {
buildMap(value, newPath);
}
} else {
map.set(newPath, { type: _type });
}