Storing data among different routes in SPA (React, Redux) - javascript

If there is SPA application (usingReact, Redux & react-router but I guess this problem/sollution is not limited to this stack) what is the best way to maintain data between different routes (URLs) to avoid unnecessary requests ?
Example:
I have 2 views which display car entity:
CarList # /cars/
CarDetail /car/:car_id
Clicking on a representation of car from CarList navigates to /cars/:selected_car_id
When rendering CarList I have already loaded the necessary data for CarDetail of any car shown at that view.
Similar problem is with wizard-like navigation with routes like:
/do-something-on-entity/:entity_id/step-1/
/do-something-on-entity/:entity_id/step-2/
/do-something-on-entity/:entity_id/step-3/
What is the best way to avoid that additional requests ?
Is usage of routes good idea in such a wizard ?

Related

Best way to create dynamic navigation on NextJS with firebase?

I'm looking forward to create a web app with NextJS and Google's Firebase. The app has an admin panel and a public site. In the admin panel should have options to edit the public site's navigation.
So I was thinking is it wise to have client-side fetching navigation data on each refresh or is there a better way to get dynamic and up-to date navigation data with as little API request as possible?
This really depends on your use case. In Next.js there are 3 diffrent types for data fetching.
Static site generation - SSG
This fetches the data and renders the pages on build time. This is greate for Pages that don't change to often. Like a blog for example.
Server site rendering - SSR
This fetches the data and renders the pages on each request from a user. This is usefull for data that changes quickly and has to be up to date.
Increment static regeneration - ISR
This allows for a compromise between the 2 types i described above and might be what your looking for if you want to use as little API requests as possiblie. With it you can staticly regenerate the page at a certain time interval.
export async function getStaticProps(){
//fetch data from firebase ...
return {
props: { data },
revalidate: 60,
}
}

Wildcard route for static content in Angular 7

I am learning Angular 7 by studying this example app. The example app uses a wildcard route to handle all otherwise-unhandled routes.
Specifically, this app-routing.module.ts directs all miscellaneous routes to AppConfig.routes.error404, which is handled by Error404PageComponent.ts, which then ultimately serves up error404-page.component.html for every possible route that is not specified by its own component and named route.
What specific changes would need to be made to the code in this sample app in order for the wildcard route serve different static content for different submitted routes?
For example, if a web user typed in the route /i-am-a-jelly-donut, what changes would need to be made so that the request would 1.) continue to go through Error404PageComponent.ts, but have the user's browser receive a new i-am-a-jelly-donut.page.html instead of the error404-page.component.html view?
The Error404PageComponent.ts would still serve up error404-page.component.html for every non-specified route. However, we would be adding logic to give special handling inside Error404PageComponent for a specific static route in addition to the logic for every non-specified route.
The goal here is to be able to handle static routes without having to create a separate component for each and every route. Think, for example, of a blog where most of the routes have an identical template, but with different content in each blog entry.
Templates are compiled into the components at build time and you are not going to be able to change which template a component uses at runtime but you can hide and show sections based on conditions. Inject the router into your component
constructor(private router: Router) {}
Now you can set a variable on your component based on if the route contains 'i-am-a-jelly-donut'
jellyDonut = this.router.url.indexOf('i-am-a-jelly-donut') !== -1;
and in your template
<ng-container *ngIf="jellyDonut">
Jelly Donut
</ngcontainer>
<ng-container *ngIf="!jellyDonut">
Other stuff
</ngcontainer>

Disable vue-router for certain routes? Or how to run SPA backend, and non-SPA frontend?

so I'm developing a website/webapp in Laravel 5.3, and Vue 2. SEO is important, so I'm wanting to keep the frontend/crawable section of the site in Laravel + Blade, and only small non necessary sections in Vue 2.0, so I've not got to use Ajax to load the page content, and allowing crawlers like Google to crawl and index the site. (AFAIK, Google does load JS, but doesn't wait for Ajax to load, so it's hit/miss).
However, on the backend, I want to go fully SPA with Vue and VueRouter.
How do I best separate the two?
I want my backend to be accessible via /manager
My solution so far is to:
# routes.php
### Laravel/Frontend routes go here (before SPA) ###
Route::get('/manager/{spaPlage?}', ['middleware' => 'auth', function () {
return view('manager.index');
}])->where(['spaPlage' => '.*'])->name('manager.index');
and then in Vue, I use:
const routes = [
{ path: '/', name: 'dashboard.index', component: require('./pages/manager/Dashboard.vue') },
{ path: '/categories', name: 'categories.index', component: require('./pages/manager/categories/Index.vue') },
{ path: '/category/:id', name: 'category', component: require('./pages/manager/categories/Category.vue') }
];
const router = new VueRouter({
routes,
base: '/manager'
})
const app = new Vue({
el: '#app',
router
...
Which does work. However, it doesn't feel right. Because the view router still loads on my frontend (appends hash/hashbang).
So, is there a better way to separate my Laravel frontend with my Vue SPA backend?
Just to clarify some misconceptions for anyone in the future.
Google can crawl JS based front end websites without the need to pre-render or server-side render. With one caveat, Google uses Chrome 41 to crawl and render the site, so your javascript has to be polyfilled at least well enough to support Chrome 41 features (or at least your Vue-based data needs to be polyfilled to support Chrome 41). I haven't had any trouble just using babel thus far.
Laravel frontend with my Vue SPA backend
This is backwards. If you are doing this, don't. Laravel should be your backend & frontend (via blade + bootstrap + Vue/react), or your backend only. Vue.js is a frontend framework and shouldn't be used as a "backend." All your database queries, authentication, calculations, emailing, etc. should be handled by Laravel. Laravel is great for backend work and it's completely reasonable to code an entire API up with laravel and use Vue exclusively for front end. Sure you might be able to hack it together and make it somehow work, but you shouldn't, and you'd just be creating extra headache for yourself for no reason.
But to also answer the question, because there is a case to be made for a website that has only part of it's site as an SPA (maybe the blog is an SPA site, but is complete separate from the "about us", "contact us", etc like pages (for instance, you might be revamping a website in parts, and would like to roll out updated pages over time instead of tackling everything at once). In this case you can specify specific routes for Vue Router to run on, and all others will be handled by laravel.
Route::get('/DIR/{vue_capture?}', function () {
return view('vue.index');
})->where('vue_capture', '[\/\w\.-]*');
This would allow Vue Router to handle everything in the DIR sub directory, but allow other routes to coexist along side of it.
But if your application requires Vue Router to have access at the root domain, then just put that at the very end of your routes file, because when route matching is done, it quits after the first match. So by placing it at the end of your routes file, you are essentially using it as a "catch all" for any routes not specified above it. Think of it like returning early.
For anyone who comes across this, I wasn't able to find anything on disabling VueRouter for specific links. I don't think it's possible, also, it's probably not worth the hassle.
So I've decided to re-write all my codebase to be a SPA. It's about time, and there's no real reason not to. I'm using Prerender.io's self hosted service for pre-rendering for SEO, etc.

Marionette building re-usable sub-apps and modules

I am currently building a complex marionette application and have been follow a great book as a reference. However, I am a sucker for reusable code and like to keep things flexible as possible.
My application has various screens and modules, one of which is a dashboard. The dashboard has its own set of responsibilities, so I made the conclusion that it should be a sub-app.
The dashboard is split 50/50 and there are two components inside. I have identified that each of these components (lets say compA and compB) each have their own set of responsibilities aswell and should be their own sub apps. However, I will have the use case where compA will be used in another area of the application.
My first thought with re-use in mind was to simply re-use the views and create a new module where ever this particular view was needed. However, the unique events and actions that come with this view are stored in the controller and API to interact with the module.
So I have ended up with the following structure:
application.js
apps
--dashboard
--compA
--compB
and I have implemented something like the following to reuse functionality from compA
Controller = {
getView: function () {
return new Show.MyView();
}
}
API = {
getMyView: function () {
return Controller.getView();
}
}
App.reqres.setHandler('compa:get:view', function () {
return API.getMyView();
});
Doing this allows me to request a new instance of the view to display and keep the same action logic. However, this means that there is no separation between each section (compA in the dashboard, and compa in another section of the app). So if I were to stop the compa module it would not have the desired results.
Is there a better approach to re-usable modules with minimal duplication of code?
My thought was to extract the Controller logic into a controller object that I can extend, and then creating a new 'sub app' when I would like to re-use the features.
application.js
apps
--dashboard
--compA-dashboard // new instance of Controller
--compA-somewhereelse // new instance of Controller
--compB
It seems as though I may be over-complicating my design pattern.
Allow me to rename your "component" as "widget" at first. In my opinion "component" is better for things more general than the widgets in your case.
I would arrange those widgets as following:
app.js
/app
/dashboard
/show
show_controller.js
dashboard_app.js
/other
/components
/widgets
/widgetA
widgetController.js
widgetView.js
/widgetB
Since widgetA is dependent from dashboard and is supposed to be use elsewhere, it should be fully decoupled from dashboard.
The 'show' View of Dashboard should have a Layout to define where to show widgetA and widgetB.
Then, in your DashBoardApp, set an appRoute to respond to some route, and then call the controller.
The controller will initialize the Layout.
The Layout will ask for show of RegionA and RegionB.
Listen to 'show' events of RegionA and RegionB, to ask for an App wide request
this.listenTo(regionA, 'show', function(){
App.request 'widget:a:show'
});
Then in Widget module, respond to the App events and deliver the view
App.reqres.setHandler('widget:a:show, function(){
API.getWidgetAView();
});
The later part of my answer is a bit vague with less code. The basic idea is, DashBoardApp should finish his job by sending App request. And then it's components job to deliver the view upon App request, which is fully decoupled.

Multiple routers vs single router in BackboneJs

All examples on Backbone I've seen use one router for the whole application, but wouldn't it make sense to have a router for each single part of your app (header, footer, stage, sidebar)? Has anyone built apps with more than one router and what are your experiences?
Let's think about a complex app with nested views: Wouldn't it be better when a view has its own router that handles the display of the subviews, than having one big router that has to inform the main view to change its subviews?
The background of this question: I've see a lot of parallels of the router in backbone and the ActivityMapper in GWT. The ActivityMapper is only responsible to get the right presenter for a given route and a given container in the DOM.
i wrote an app (still writing) with multiple routers in it.
however it is not like you think, it is more module based and not a router per view or anything like that.
for example,
say i got two big modules in my app, 1 handling all books, and 1 for the users.
books have multiple views (as do users), a list view, detail view, edit view, etc etc...
so each module has its own router,
which stands for its own set of urls:
// user module...
var userRouter = Backbone.Router.extend({
routes: {
"users": "loadUsers",
"users/add": "addUser",
"user/:id": "loadUser",
"user/:id/edit": "editUser"
}
// ... rest dropped to save the trees (you never know if someone prints this out)
});
// book module
var bookRouter = Backbone.Router.extend({
routes: {
"books": "loadBooks",
"books/add": "addBook",
"book/:name": "loadBook",
"book/:name/edit": "editBook"
}
// ... rest dropped to save the trees (you never know if someone prints this out)
});
so, it is not like my two routers are competing for the same route, they each handle their own set of routes.
edit
now that I had more info via Elf Sternberg, I know it isn't possible by default to have multiple routers match on the same route. without a workaround like overriding the backbone history or using namespaces in routes and regexes to match these routes.
more info here: multiple matching routes
thanks Elf Sternberg for the link.
I just wrote a blog post on Module-Specific Subroutes in Backbone, which allow a "subroute" to be defined which pays attention to everything after the prefix for that route.
Check out the blog entry for more explanation: http://www.geekdave.com/?p=13
This means you don't have to redundantly define the same prefix over and over, and you can also lazy-load subroutes as modules are accessed. Feedback is most welcome!
There is a limited but important case when it makes sense to use multiple Routers. If you need to expose only a subset of your application's routes & views based on data collected at runtime (perhaps login credentials - e.g., manager vs. staff can see & navigate between different sets of views) you could instantiate only the appropriate Router & View classes. This is significant because routes can be bookmarked and sent from user to user. Of course, you still need checks on the server to ensure that an unauthorized user isn't issuing requests after navigating to a view they arrived at via a bookmark sent by an authorized user. But it's better to design the application so the unauthorized view is just not generated.

Categories

Resources