feat: add destroy function to root api (#1691)

* feat: add destroy function to root api

* chore: don't modify ref

* chore: clean up a bit
This commit is contained in:
Tobias Åström
2025-03-24 16:36:50 +01:00
committed by GitHub
parent 15c83cdb55
commit ee7171e5ed
6 changed files with 31 additions and 8 deletions

View File

@@ -87,6 +87,7 @@ export default function boot({ app, context }) {
);
const cells = {};
const cellsUnmount = {};
const components = [];
return [
@@ -97,11 +98,14 @@ export default function boot({ app, context }) {
});
},
cells,
addCell(id, cell) {
addCell(id, cell, unmount) {
cells[id] = cell;
cellsUnmount[id] = unmount;
},
removeCell(id) {
delete cells[id];
cellsUnmount[id]();
delete cellsUnmount[id];
},
add(component) {
(async () => {
@@ -136,6 +140,12 @@ export default function boot({ app, context }) {
appRef.current.setContext(ctx);
})();
},
destroy() {
Object.keys(cellsUnmount).forEach((c) => {
cellsUnmount[c]();
});
modelStore.destroy();
},
},
modelStore,
selectionStore,

View File

@@ -40,12 +40,11 @@ export default function glue({
root.remove(portal);
model.removeListener('closed', unmount);
};
model.on('closed', unmount);
root.add(portal);
// Cannot use model.id as it is not unique in a given mashup
root.addCell(currentId, cellRef);
root.addCell(currentId, cellRef, unmount);
return [unmount, cellRef];
}

View File

@@ -332,6 +332,10 @@ function nuked(configuration = {}) {
}
return createSessionObject(cfg, halo, modelStore);
},
// TODO - document
destroy: async () => {
root.destroy();
},
/**
* Creates a visualization model
* @param {CreateConfig} cfg The create configuration.

View File

@@ -3,6 +3,7 @@ import { useState, useEffect } from 'react';
export default (initialState = {}, applyMiddleware = () => {}) => {
const sharedState = initialState;
const hookListeners = [];
const subscribedListeners = {};
const store = {
get: (key) => sharedState[key],
@@ -11,7 +12,7 @@ export default (initialState = {}, applyMiddleware = () => {}) => {
throw new Error(`Invalid key: ${JSON.stringify(key)}`);
}
sharedState[key] = value;
applyMiddleware({ type: 'SET', value });
subscribedListeners[key] = applyMiddleware({ type: 'SET', value });
return value;
},
clear: (key) => {
@@ -23,6 +24,11 @@ export default (initialState = {}, applyMiddleware = () => {}) => {
dispatch: (forceNewState) => {
hookListeners.forEach((listener) => listener(forceNewState ? {} : sharedState));
},
destroy: () => {
Object.keys(subscribedListeners).forEach((key) => {
subscribedListeners[key] && subscribedListeners[key]();
});
},
};
const useKeyStore = () => {

View File

@@ -18,6 +18,7 @@ export default function initializeStores(appId) {
modelChangedStore.dispatch(true); // Force new state to trigger hooks
};
const unsubscribe = () => {
model.removeListener('closed', unsubscribe);
model.removeListener('changed', onChanged);
rpcResultStore.clear(model.id);
rpcRequestStore.clear(model.id);
@@ -30,9 +31,7 @@ export default function initializeStores(appId) {
case 'SET':
if (!initialized) {
model.on('changed', onChanged);
model.once('closed', () => {
unsubscribe();
});
model.once('closed', unsubscribe);
}
break;
default:
@@ -51,8 +50,13 @@ export default function initializeStores(appId) {
};
};
const destroy = () => {
modelStore.destroy();
};
return {
subscribe,
destroy,
useModelStore,
modelStore,
useModelChangedStore,

View File

@@ -189,4 +189,4 @@
}
}
}
}
}