I'm having an issue thinking about the best way to architect a React app with multiple pages/views (still a SAP).
Let's say we have a simple app with 4 major sections (pages): dashboard, users, stats, comments. Each section has different components in it (think react components). For example, the comments section would have a hierarchy like so:
CommentsSection
- CommentsQueue
-- Comment
--- Text
--- Buttons
- CommentsApproved
--Comment
--- Text
--- Buttons
In a framework like angular for example, the 4 main sections would be split into partials, and loaded in an ng-view upon request, with their respective components inside. When landing on the homepage, the app would only load the dashboard view and upon the user clicking on a nav item, the selected route (i.e. app/users or app/users/:id) would trigger and the app will load the required "template-view-partial" (without a browser refresh).
Now in terms of React, how would this occur? it seems like ALL views and ALL their components would need to be available in a browserified JS file and the app can then update the DOM.
This seems terribly wrong, as we'd be loading all sections in the first load, even if the user doesn't ever need to get to that section. Granted, we could split it with routes on the server, and only serve the components for the page based on the route, but that would require a browser refresh, where as in Angular for example, it would happen without a browser refresh as the view is loaded asynchronously.
The question is, how can this asynchronous loading happen in a React-based app?
I think there's a few different ways in approaching this, I'll explain the approach that I am currently using for my work and side projects.
Instead of using browserify, we use a module-bundler called webpack (https://github.com/webpack/webpack). What's great about webpack is that it's like Browserify but can split your app into multiple 'bundles'. This is great because if we have multiple components/views, the user would just download the features they need for that particular view without having to download everything initially. It allows react-components and their dependencies to be downloaded on demand.
Pete Hunt wrote an article that goes into depth on the benefits of webpack when using it with React (including how to async load react components), and how it is similar/different to Browserify and modern build tools like Grunt/Gulp: https://github.com/petehunt/webpack-howto
I have described one solution using webpack here : http://blog.netgusto.com/asynchronous-reactjs-component-loading-with-webpack/
In essence :
use require.ensure([], cbk) to define code chunks; in the cbk, load your packages synchronously using require()
in your host component, load your asynchronous component in componentWillMount(), and set in in the host component state.
use it in the host component render, when defined on the state
Related
I recently started working with Angular 6 and while basic scenarios work pretty well, I'm having a hard time making more complex routing scenarios work.
I have so far divided my application up into two major modules (more to come), Authentication and Core.
In the Core module, I have a Core Component which contains Navigation, Header and Footer Components and then a tag.
From the core navigation the user should be able to access major parts of the application such as:
UsersModule - UserListComponent, AddUserComponent, EditUserComponent etc
ProductsModule - ProductListComponent, AddProductComponent, EditProductComponent etc.
As these different modules will be used by different users I was hoping to use lazy loading to load them into the CoreComponent - router-outlet tag. Ultimately it will look like this:
The problem is I'm not sure how to set up my routing as when I try to load any of the components in either UserModule or ProductModule they just replace the contents of the screen instead of being loaded into the CoreComponent's tag.
Here is the code:
app.module.ts
core.module.ts
user.module.ts
Can anyone please help me?
I' am looking for a way through which I can load multiple modules under same path in Angular. For example, consider I have three modules AModule, BModule and CModule each having its own RouterModule.forChild call. Now I want to mount all these modules under say site route.
One way I have achieved this thing is by wrapping routes in RouterModule.forChild call under site route as follows:
RouterModule.forChild([
{
path: 'site',
children: [{}] // children goes here
}
])
I don't know whether this approach is correct but it is working fine. The only issue which this approach is that I have to specify canActivate in every module I want to mount under site. While this is not a problem, I was looking for a cleaner solution.
I know there is a property loadChildren which could be used to load modules lazily. But I want to load modules eagerly.
I' am using AngularCLI which splits code of module I specify in loadChildren in a separate JavaScript file which is not I want.
I' am using AngularClI v1.2.0 and Angular v4.2.5.
Any help is highly appreciated.
Thanks
I'm not entirely clear on your goal and what you are ultimately trying to achieve, but here are a few thoughts.
You can use the loadChildren and "lazy loading" to load on demand OR eagerly. If you select eagerly loaded routes, as soon as your main route is loaded and your first view is displayed, the other modules marked for eager loading are immediately loaded asynchronously.
I have an example of that here: https://github.com/DeborahK/Angular-Routing in the APM-Final folder.
I'm not clear on why you don't want module splitting. It can significantly improve the startup performance (time to display of the first page) of your application.
In addition to canActivate there is also a canActivateChild so you can put this on the parent and not have to repeat it for each route. The docs for that are here: https://angular.io/api/router/CanActivateChild
I had an issue yesterday that you can read about here and it relates. I thought that changing my directory name was messing up my react components, but I think I figured out the problem.
I'm building a web app with node/express/react and I'm rendering react server side and creating a bundle.js file to use client-side. I have multiple react components that I'm rendering on the page, but they're not all in the same 'react app'. Basically I have a few 'mini react apps' so each set of functionality has its own ReactDom.Render call.
for example, I have a form at the top for adding new items, that has its own render, and I have a list of items below that, that has its own render call. and both of these mini-components are bound to separate divs.
<div id='the-form'><%-form%></div>
<div id='the-list'><%-list%></div>
however, it looks like the component that comes first in the bundle.js is the one whose render call is working, the other component(s) render initially from the server-side rendering, but then there are no updates because the components are not re-rendering/updating.
is there a way to keep my approach but have these working?
Remove window.onLoad and just use ReactDOM.render alone.
I would like to add a Javascript function to all pages within the store that installs my module.
I read up on hooks, and it seems that there's no single "display" hook that I can count on being called for every single page in the store - different pages have different hooks. E.g. I need to use the displayHeader hook for "Home page and general site pages" but this doesn't work for product pages.
Is there a way to do this with a single hook, not a list of hooks each for a specific page category?
Note that I don't want to use a theme for this, because my module is meant to be an add-on to the store, not an overarching design template.
Edit:
I was wrong saying that displayHeader hook doesn't work for product pages. Indeed, as the answer says, that's the one that I need to use.
you still can use this call
$this->context->controller->addJS($this->_path.'your.js');
in module hookDisplayHeader() method, it will register your js file in js files list that will appear in e.g. header.tpl loop by $js_files
P.S.
also do not forget about mobile with somethign like:
public function hookDisplayMobileHeader()
{
return $this->hookHeader();
}
so module should be registered in 2 hooks Header and mobileHeader to appear on all devices.
At the moment we are in the process of creating a new web application infrastructure.
We initially load a dashboard which is esentially the top bar displaying the logged in user and the set of menus along with it. Clicking on each menu would load a screen (mostly crud screens) in the main section. We areplanning to put each of the crud screens and their components (services, controllers and such) in a seperate module which will encapsulate all the screens from each other, so for example if there is 78 screens there will be 78 seperate modules for each screen. We are also using planing on using Requirejs to load these dependencies dynamically.
The problem however occurs that we need to link the menu with each of the modules for each screen. Typically in a single module based app it would be done like this.
config(function($routeProvider, $locationProvider) {
$routeProvider
.when('/Book/load', {
templateUrl: 'book.html',
controller: 'BookController'
})
.when('/Screen/load', {
templateUrl: 'chapter.html',
controller: 'ChapterController'
});
Where the BookController and ChapterController will be in the SAME module.
However in our case the BookController will be in a BookModule for the book screen and the same applies for the ChapterController. And the routes would be in the initial main module for example AppModule which loads the dashboard initially during startup then.
How would we say for example link the AppModule and the routes with each module for each screen (for example in this case BookController and ChapterController) keeping in mind that we need to load the modules dynamically when NEEDED using requirejs.
(P.S : We are essentially segmenting our application based on feature where feature in our system usually equals screen)
Also any suggestions on any other way we could best structure our app including an answer to the above problem would be very much appreciated.
Regards,
Milinda
Why do you have the route configuration in the initial main module? This creates unnecessary coupling between your modules (ie. your initial module has to know all the possible routes of every module), sort of defeating the purpose of moving your code into modules in the first place.
Each of your modules can have their own route configuration, which will take effect when the modules are loaded. (A consistent naming convention can help avoiding clashes between routes of unrelates modules)
While configuring the routeProvider, you can use lazy loading mechanisms using the resolve attribute of routes: resources referenced here will be resolved before the routeChange event happens, which enables you to wait for any promise resolution or a requireJS loading of a file. This blogpost might help in that regard.
As of this moment, there is no mechanism as far as I am aware for dynamically loading modules at runtime and then incorporating them in an AngularJS app. You can breakdown your app into 78 individual modules loaded via requirejs, but you will still need a single primary module which has all those other 78 as dependencies. It is this primary module which you will then configure all the routes.
There is work going on into a new AngularJS router which borrows from other more flexible routers (i.e. ui-router, etc) which will allow exactly the sort of dynamic loading of modules you are speaking about but as far as I know it won't be available until AngularJS 1.4.