React.js: Can certain components be made SSR-rendering only? - javascript

Coming from some classic server-side template languages (php, jsp), I have a general architectural question on React.js:
Can I limit certain components of a page to be rendered server-side only? And reduce the client-side javascript bundle accordingly?
*I find that often ridiculously large. One reason (afaik): Every component must have the capability to be re-rendered on state changes and SPA-(aka soft, virtual..) page navigation, since all changes come in as data, not as prerendered html chunks (afaik).
Basically, I see 2 different types of content sections in almost all of my web projects:
1) highly dynamic “facebook-ish” interactive sections
Personal greetings, messages and message counters, likes and replies… here default React behavior is at its best: new data comes in, global state (redux store) changes and all affected components get re-rendered. Which would be a daunting task without react and redux sound principles. And certainly client-side rendering/updates are the way to go.
That's often the user-login area at top ("Hello Joe, 5 unread messages"), some live data (stock, weather,…) in the middle and said comments closer to the bottom.
2) SSR “static” content (think PHP)
However, for many sections I know for sure, nothing is client-side dynamic. Footer Menus for example, might stem from a database, but are certain to not change for the duration of the session. (Even if John Doe decides to like, comment or change his name…)
Rendering them only server-side would be enough. Often the main content block can also do with SSR-only. (And all the layout-ish sub-components needed to render its html)
Still, I have to give all components to the client bundle, so that also virtual/soft page navigation works... (which transmits new data, but not pre-rendered sections)
You could tell me as a workaround to simply keep the footer out of the react container mounting point, but that's not my point... "static" aka sections that can do with pure SSR might be elsewhere, too, between dynamic header and lower response/feedback/liking sections…
I would like to mark Type-2-components as "SSR-is-enough" (and also their sub-components – unless webpack dependency tree figures out, they are used in Type1-CSR-components, too…).
So send it as a single html blob. Also receiving it "pre-rendered" on SPA-ish virtual page navigation would be needed afaik. (since the component knowledge will be missing from the client bundle)
Is there a way to do this? Has someone thought of this general, imho common problem before...?

Hydrating only certain components is definitely a problem that is being thought about.
One web framework that solves is problem is Astro. It only hydrates components which are actually interactive.
Another is Fresh, which has a concept called "islands." The entire page is server-side generated and when you need interactivity, you create an "island" which is a component which is hydrated on the client.

Related

Next.js favorite list best practice

I have a next.js application with redux and a node.js Rest-API. You can view items and as often you can store favorites.
Now the view component of the items and the favorites is obviously the same.
I have now two options how I can do it and I want to ask you what is best practice with next.js:
1.Option:
Have two routes. One called "search" and one called "favorites".
Pros:
Clean approach as everything is clearly separated from the root
Cons:
Have to remove full DOM and add full DOM just to show favorites - which is essentially the exact same view
2.Option: One route called "search" with a prop for the section
Cons:
Unclean IMO since I need to add a prop to many components
Pro:
For me seems to be way faster
Redux store is organized the following:
{
search:{
results:[],
total:0,
},
favorites:{
results:[],
total:0,
}
}
It's hard to provide a concrete answer to this question. Do you want one page for users to browse items, allowing them to filter by which ones they've favorited, or do you want one page for searching items regardless of which ones they have favorited and a separate page for finding favorites? This doesn't seem like a best practices problem, it's totally your choice. That said, I would probably prefer option 1 because that is how most applications do it. The fact that it is slow is weird—next.js tends to be very good about preloading. Give your page(s) a try in production mode—often Next.js is just slow to build them in development mode and the real page your users will face will be much faster.

Vuejs: distribute code across multiple components or everything into a single component?

So I've played a lot with Vue, and now that my app has become large, I am having doubts about how to organize it.
I understand components and that they make sense when you need to re-use them many time on the same page, for example, a "custom select box" component, that will likely be needed in many places.
But what about components that will only have once instance? Example: a administration dashboard interface that has 3 areas: a sidebar with some navigation, a main area with stuff you can edit, based on what is selected in the navigation, another sidebar with stuff related to the main area. Do all these need to be separate components? Because I don't see any benefit of doing that if there is only one instance of each on the page. On the other side, if I stuff all the code in a single "app" component, I could simplify some of the code (less variables)
Summary - typical reasons for using components:
Maintainability.
Rendering performance via component boundaries.
Loading performance via chunking.
If you find that using fewer components improves maintainability then that's fine. It may well be the correct design for your application.
Verbose version below.
The primary reason for using components is to improve maintainability.
Components that are reused in many places such as a select-box are obviously easier to maintain than repeating the same code over and over. However, it is worth considering why that is. It's not just that duplication makes it more difficult to make a change to all of the select-boxes. The other key benefit of using a component is that the extra level of abstraction can reduce mental overhead.
Let's say someone trying to maintain the code sees something like this (pseudo-code):
<select-box :some-prop="blah">
<select-box-option v-for="something" />
</select-box>
Immediately it's clear that this is a select-box. All the gory implementation details of the select-box are hidden away and we don't need to worry about them. By looking at the props, child components and events we can quickly deduce what data goes back-and-forth between the parent component and the select-box. This is just separation of concerns.
This benefit also applies to components that aren't reused. Let's take the sidebar example. We might see this in the template for our main component:
<nav-sidebar #navigate="onNavigate" />
The component's name allows us to quickly identify it as the sidebar. If our current task doesn't involve the sidebar then we can just skip over that bit of the template. As the code has been moved off to a different file we have no difficulty establishing which bits of the code are part of the sidebar and which bits aren't.
In this example the nav-sidebar doesn't have any props and only has a single event. From that we can start to draw some conclusions about how these components interact. It would seem that the nav-sidebar doesn't need anything passed from the main component, it could quite happily live stand-alone. If we need to debug a problem with data flowing the other way we'd almost certainly start with onNavigate.
We couldn't start making deductions like these anything like as quickly if everything was mangled together into one, big component.
Of course it could be that our deductions are wrong. It could be that the nav-sidebar does some horrible things involving $parent to grab data from its parent component. However, that just illustrates why using such techniques is considered bad practice. Maintainable code should allow developers to jump to reasonable conclusions based on the abstractions that appear to be in place.
But it is possible to go too far the other way.
A good abstraction allows you to free up some mental capacity by hiding details behind a label. A poor abstraction adds mental overhead by hiding the code you want to see behind some indirection. Add to that the difficulty of naming things and the burden of extra glue code and you may well be better off just ditching the extra layers and keeping everything inline.
The other thing that can go wrong is splitting components up in the wrong way. Separating concerns requires clean partitions of those concerns. Chop things up slightly differently and you end up with a single concern being spread across multiple components and the resulting mess is typically worse than if you hadn't bothered splitting things up at all.
Vue allows you to split up your JavaScript code in a number of ways, components being just one. Separate .js files, plugins, filters, Vuex, mixins, etc.. There are several options available to you.
Templates, on the other hand, can only really be split up by using components. If you want to break a huge template down into more manageable chunks then components are really the only way to go.
This brings us to another key reason for using components.
A template is compiled down into a render function. When that render function is run it registers reactive dependencies, just like a computed property. If any of those dependencies changes it will trigger a re-render. That runs the whole render function again. Even if that doesn't result in any changes to the DOM it will require the generation of all the relevant VNodes and the diffing algorithm will need to check all of them.
Component boundaries are also rendering boundaries. Each component makes its own decision about whether or not to render based on whether its dependencies have changed.
So, taking the nav-sidebar example, let's say something changes in the nav-sidebar so that it needs a rendering update. If the nav-sidebar is a separate component then it just needs to run the template/render function for that component. If instead we bundle all the nav-sidebar code into the main template then we'll have to re-render everything.
Vue also has support for lazily loaded components as a way to reduce the initial load time of the page. The idea is that many applications have large sections, such as admin interfaces, that aren't relevant to most users. Rather than incurring the overhead of downloading all of those components you can split the components into chunks and download the chunks when they're needed. This is usually implemented via the Vue router configuration.
Chunking aside, the typical way to use the router is to have separate components for the different pages. While in theory it is possible to use the same component for all routes that is unlikely to lead to something more maintainable. I would add that the definition of 'page' is a little fuzzy here but in most applications it's clear what constitutes a different page, resulting in a different component.
No tome on creating code monoliths would be complete without some mention of testing. Unit testing should be thought of as a form of reuse and a particularly extreme form at that. Tests have an unrelenting knack for exposing the mess of spaghetti that hides behind what you thought was a nice, clean design. I'm not going to pontificate on testing but suffice it to say that you won't be able to write unit tests unless you split things into suitable units.
Another key feature of a component is that it has its own set of properties. Its own data and its own computed properties. This sounds obvious but it gains significance when you consider looping via v-for.
<div v-for="item in items">...</div>
The example above uses inline elements instead of components. Any state can only live on the parent. That state needs to be held for each loop item, so we may end up with multiple arrays holding different aspects of the state. Computed properties are similarly difficult to implement when working with loops. We typically end up using methods instead:
<div v-for="item in items" :class="getClassesFor(item)">...</div>
Now consider the component version:
<my-component v-for="item in items" :item="item" />
Each my-component can hold its own state. Let's say, for example, that my-component has expand/collapse functionality. That can now be stored in a local data property within each instance. Likewise each instance will have its own computed properties.
Arguably this is just reuse as the v-for creates multiple instances. However, given we're specifically introducing a new component just to provide a form of property scope, I think it warrants a special mention.
I personally like to have 3 types of components.
Reusable system component. These are used for generic layouts, custom buttons, custom select box ... They are meant to be reused multiple times in the code and be very versatile.
Page/View component. The route usually routes to a specific component. This component is some kind of assembly of multiple components. The distinction allows to quickly identify the "page" of the application.
Logical division. These are the hardest to find. I tend to isolate things that are not related to each other. For instance, a footer may not be reuse but a modification in the footer should concern only the footer. Other examples are the navbar, the menu, each section of an admin. These components should be reusable as much as possible but sometimes they will be specific.
Another example: A comment system. A "comment" would be a component of type 3. A "comment thread" display would be another component of type 3 that use the "comment" component. A page would exist for the subject of a comments thread and would be of type 2.
Note that each component of type 3 and 2 may use other components of other types.
If I want to change the display arrangement of the comment thread I only have to change the "comment thread" component.
Vue components uses not only for re-use. You may split components into logical blocks. SPA for example. You can create grid based on vue components.
Here is the reason why you need to split codes even it is used only once.
With hundreds or thousands of lines of code, it's no question that
splitting code in different files can help make it more manageable.
Although, this can quickly turn into a complicated mess if the
splitting isn't thought out beforehand.
The more you split codes, the clearer it becomes.
It does not only work for Vue JS but also works for almost programming languages.

Vuetify performance issues

I have picked vuetify for an offline PWA project where I work with indexed DB and some notable size data (5k-6k/collection). I have to transfer it between vuex and IDB after I get them from the server.
Reading and saving them is kinda slow (200-300 ms), and freezing the UI for a short time. I thought making a full-screen loading screen while it was loading helped, but it still make the loader stutter.
Also, I have some problems when I am navigating between pages. Loading v-lists (with infinity loading) and swiper (swiper slider) freeze the UI and it feels a little bit off. Especially, when I am adding vibrating to the buttons. The freezing delays the vibration for 100-200 ms and I don't know I am touched the button or not.
Things I've tried so far:
Looping through the list elements, and freezing the objects at vuex mutations (I want to keep the reactivity for array methods). It feels faster, however cloning arrays can delay the initial loading. And still not satisfying.
Using requestAnimationFrame solves the freezing at navigation, but delays the rendering of childcomponents. Also doesn't seem like the best solution.
Using less dom elements. I'am using infinity scrolls for v-lists. It still loads slow despite it only rendering 15 rows. I cannot use a virtual list, because the list elements have different heights. I didn't find a carousel/swiper with
proper virtualization. Vue-awesome-swiper is the most popular, but it loads incredibly slow.
My app
Sadly I cannot share the project here, But I don't use any extraordinary code, that's why I am confused about the low performance.
At service workflow
Getting data as JSON from the server -> vuex action -> committing mutation and saving data to IDB with Dexie's bulkPut -> mutation freezes the objects and saves to the state
At visualization
components using mapgetters to get the lists from vuex. Using these getters, I am making computed properties to filter/reorder data (these methods run under 30ms, so they shouldn't make issues).
I couldn't find any helpful information on how to make my application faster. Even scrolling down the list seems slowy/laggy. I could use webworker to handle IDB at initial loading, but the UI animations would still be slow. Should I use less v-container/v-layout/v-flex etc... and adding native elements to my app? Currently, I am using only vuetify elements.
As I am loading all my data at starting, I am expecting a slower initial loading time for sure, but smooth navigating and fast loading after that.
My site is entirely on Laravel and Vuetify technology. Just a few recommendations. First, there must be a very fast server. Not average in terms of speed, but a fast one. Secondly, the page should not have full-page Vue components. They are first mounted, then displayed. The user sees this as a display after some delay. Further, there should be no data loading via the API after the layout is displayed (the getData method in the mounted hook). And, of course, loading a large amount of data via prop {{json_encode($data)}} delays and degrades performance.
We've built an application with vue/vuetify, where the main component is a complex multidimensional grid generated on the fly.
Our first iteration was painfully slow, once, with meaningful data, we got a rendering time of 9 sec ...
The solution to our problem was two fold:
use functional components wherever possible,
use Object.freeze on data that doesn't need to be reactive (as mentioned) - at this link an explanation of the optimization technique
Now rendering the same component takes fractions of a second.
From the doc:
Functional components are an alternative form of component that don't
have any state of their own. They act like pure functions: props in,
vnodes out. They are rendered without creating a component instance
(i.e. no this), and without the usual component lifecycle hooks.
as always, just my 2c :)

How can I improve the performance of passing around a large JSON object in React Native?

I'm building an app with React Native and on my transitions, where I'm loading more data, it's very slow and I'm wondering if there's a better way to structure my app to avoid these shutdowns, which get longer as the JSON file gets larger.
Let's say I have
var data = require('./data/data.json')
in my index view, I think pass this data to a view, which then splits it up to other views like items={data[section_name]} and it goes down recursively like that further down the hierarchy. Creating smaller dicts on each level. And even with small objects it is still quite slow.
The JSON files I'm working with are from 3-8 MBs.
I understand what you want do to with your big data in your project, because I did the same way before for my react-native app.
Actually, this way is fine, it's kind of loading the data once only, then we can retrieve hierarchy easily like items={data[section_name]}
However, the problem now is it may take a while for processing the big data!
Therefore, the idea is we should move the part of loading/initializing the data asynchronously, move it somewhere out of our view, so that the view's transition as well as its other things will not be affected! Then, when the data are being loaded/processed, we may show something like fade-in, fade-out effects, on the view, so it will take a short-time (300-1000ms). However, in my opinion, there may be a better way for this: when the application is opened for the first time, when the splash screen is being shown (for a few seconds, this behavior is common, we can load the big data in the background here!)
FYI, my application loads big data using ajax, it will even take longer than loading local files, but using my above-mentioned way, nobody complains about the data-loading speed ^^ (actually, users don't know and don't see where and when data are loaded, when the app goes to its home/top page, everything has been fully loaded)
Now it comes to the important part of my answer: I suggest you using Flux/Redux for this, maybe Flux is easier for you now, because Redux is kind of an improvement based on Flux (in either Flux or Redux, we will have a Store, and this Store will work asynchronously, you can store your big JSON data here):
https://www.atlassian.com/blog/software-teams/flux-architecture-step-by-step
Flux can be applied on reactjs and react-native of course, you may find there are several new definitions if you don't know about Flux or Redux yet, however, it's really worth reading and trying! After you understand it, it'll be very easy and then you can apply that architecture on whatever react project you like ^^

Designing state for Reusable React Components and Browser history

I'm looking for ways to structure state in my React components so that I can accomplish two goals together: (1) managing browser history in a complex app, and (2) letting individual components be easily reusable in environments outside the main app.
The app has a Panel component which lets users navigate and read content on our site. In the main app, multiple panels can be opened and arranged together. Outside of the main app, there are other pages where I'd just like to be able to easily drop in a single Panel component.
As this code has developed so far, each Panel has a rich state representing what content it has loaded and other display settings. This makes it easy to drop in to another page - I can just render a Panel component and the user can interact with it and it takes care of itself.
For browser history however, this is getting hairy. There is an App component which manages multiple Panels and the states pushed to and popped from history. In order for it to have a complete picture of the state of the whole app, each panel pushes up a copy of its state when changes occur. When state is popped from the history that App component can pass down an initialState from each of the Panels it renders. As you can imagine, this is getting messy and error prone with the cycles of updates that end up looping back to each other.
It feels like the approach I need to take is to Centralize State (a la the recommendation here) and try to make each individual Panel stateless. Since it will be a significant effort to rewrite all the calls to setState already in the code, I'm trying to evaluate if this is the only way to go. It also feels like this approach will make it harder to reuse the components outside the app. I'll lose the feeling that a Panel is a self-contained component which I can just render on a page, since it will need some kind of outside manager as well to handle its state and all the events that change it from within.
What would you recommend?
I made a application on react and implementing react-router you can pass throw the URL data to every panel know in what state are and what content is loaded, by example you can have an url like:
http://yoururl.com/index/user/userID1/item/itemID2/filterDate?="19/09/2014"
To reuse your panels you can made a url that made an herarchical route view: You can pass throw components everything you want to know on the render wich view you have to load.
My routerDomExample
I recommend to investigate react-router.

Categories