In our react app, we are using react-router with several different routes.
What we want to achieve is to render A12 models in specific routes of our app, while others just render normal react components. We already got it working, but we are wondering if the current approach is really the best one that we could take.
So, our current approach looks like this:
- We have react-router which controls the routes:
/projects,/project/<id>, etc.
<HashRouter>
<Routes>
<Route path="/" element={<DefaultLayout />}>
<Route index element={<HomePage />} />
<Route path="projects" element={<ProjectsPage />} />
<Route path="projects/:projectId" element={<ProjectPage />} />
...
- Each route (e.g.
/projects) consists of a React component which renders that corresponding page.
As an example, here is the code for the “projects” case, which is a page that should render A12 models. Therefore it registers the respective module and launches the initial activity of it.
// ... imports omitted
import projectsModule from "@/modules/projects";
import { useRegisterModule } from "@/hooks/useRegisterModule";
export const ProjectsPage: FC = () => {
const dispatch = useDispatch();
// register the projects module for the lifetime of this page
useRegisterModule([projectsModule()]);
useMount(() => {
// here, we launch the initial activity
dispatch(ActivityActions.create({
activityDescriptor: {
module: "ProjectModule",
engine: "overview",
}
}))
})
// taken from full-stack template
return (
<AuthenticatedPage layoutProvider={customLayoutProvider}/>
);
}
Where useRegisterModule.ts looks like this:
// ... imports omitted
import { clearActivities } from "@/store/modules/app/actions";
const moduleRegistry = ModuleRegistryProvider.getInstance();
/**
* Hook for registering given modules for the lifetime of the enclosing react
* component. When the enclosing react component is destroyed, the modules are removed
* from the registered modules again.
* @param modules {Array} the desired modules instances
*/
export const useRegisterModule = (modules: Module[]) => {
const dispatch = useDispatch();
const modulesRegisterer = new ModulesRegisterer();
useMount(() => {
modulesRegisterer.initModules(modules);
modulesRegisterer.register();
});
useUnmount(() => {
// clears all activities
dispatch(clearActivities());
modulesRegisterer.unregister();
})
};
/**
* Class for registering a given modules
*/
export class ModulesRegisterer {
modules: Module[];
constructor() {
this.modules = [];
}
/**
* Sets initial modules array
* @param modules
*/
initModules(modules: Module[]) {
this.modules = modules;
}
/**
* Register given modules
*/
register() {
this.modules.forEach((module: Module) => {
if (!moduleRegistry.getAllModules().includes(module)) {
// module not registered yet -> register it
moduleRegistry.addModule(module);
}
})
}
/**
* Unregister given modules
*/
unregister() {
this.modules.forEach((module: Module) => {
moduleRegistry.removeModule(module);
})
}
}
(useMount and useUnmount do just what their name implies: run once the component gets mounted/unmounted).
- For pages/routes that should render A12 models, we use a dedicated
appmodel.jsonfile (e.g.projects-appmodel.json). The appmodel is just like anyinstaller-appmodel.json, containing some modules with their respective models. - We define the A12 Module which imports the appmodel.
TheProjectsModulewhich was previously registered within the page looks like this:
// ... imports omitted
import * as model from "./projects-appmodel.json";
const module = (): Module => ({
id: "ProjectsModule",
model: (): ApplicationModel => model as ApplicationModel,
});
export default module;
We repeat this procedure for every route/page, which should render A12 models.
The approach works, but uses also a lot of boilerplate code and still contains some dubious parts.
Now my questions are:
- Has anybody tried to implement something similar?
- Does anybody have some hints on how we could simplify our approach?
- I know that A12 doesn’t work with react-router by default. But would it be possible to somehow integrate it in the future?
