Next.js favorite list best practice - javascript

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.

Related

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.

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

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.

Redux: one form per record for potentially thousands of records

Scenario: I have a list of assets <AssetList />. As the user scrolls down to the bottom of the list my app will lazy load the rest of the assets. So depending on how far the user scrolls down, hundreds, if not thousands of assets could be loaded.
The problem: Clicking each asset <Asset /> will expand it and allow the user to edit its fields (name, content, ..) The transition should be seamless. As I see it, each asset needs to be a form. My concerns are 1) Approach and 2) Performance.
Approach: The approach I am taking here is using one form per record using redux-form. Are there any alternatives to this that also enforce the flux architecture? Is this a common problem?
Another potential approach here is to modify the state tree as such and have one form per the entire asset list:
{
assets: {..},
assetForm: {..}
}
And clicking an <Asset /> will instead trigger the appropriate action which will cascade to a reducer which will update the assetForm state.
Performance: My biggest concern by far. I don't mind the large number of forms on the page but what concerns me is that each form is associated with a redux store reducer (or at least that's what I think utils such as redux-form do). So in other words, does potentially having thousands of reducers impact performance?
My apologies if my assumptions are incorrect. I am relatively new to react & redux.
I think you raise valid concerns on a fairly common use case. To address some of your questions, I think your approach is valid except you may want to tweak it a little to avoid having so many forms created. I haven't personally used redux-form so I'll let those with more experience add more answers or comments, but from a more abstract point of view, you should only have a form when the user clicks in an Asset, therefore, I suggest only rendering the form when the Asset is clicked. This way you will only have as many forms as the user needs, dramatically less than one per Asset.
As for management of the store if you were to have to initialize a form per Asset, again without specific redux-form experience, couldn't you ensure you have a fairly simple state structure and only append to it when a form is initialized? That is, think of a state var called assetForms which is an object where each key is the unique id of the Asset and the value is another object with the form data. This way, again, you only keep as many state objects as there are Assets.
Hope that clears up some of the confusion but feel free to expand on your question if you need more specifics.

Should I use <page type="list"> or <listpage> in angular2?

I'm getting started with angular2 and wanted to create a todo-list web app. The UI should consist of two pages (=components) which get slide in/out via JavaScript.
The first one shows all todos in a vertical list and the other one shows additional details when a todo item from the list is clicked.
I'm now asking myself, what's the right way in angular2 to declare the page components?
Should I build a generic component like this?
<page type="list"></page>
<page type="detail"></page>
Or should I create a new component for each page?
<listpage></listpage>
<detailpage></detailpage>
In general, without knowing more details, my gut sense would be that the latter would be more appropriate, i.e. create a new component for each page.
You require two fundamentally distinct types of entities:
a collection and
a single item from that collection.
The first solution that you propose, i.e. a generic component, would be more suitable to multiple entities that all share some basic underlying structure but differ in some (but not all) details, e.g., two different collection views that both list all items but format those items in two different ways. To force that strategy onto your use case would require your generic page component to have no universally shared structure: what template or logic would you share between a todo-list collection and a single todo-item from that collection? Everything would depend on the value of the type attribute. Then what meaning would page have? Essentially nothing.
Your latter suggestion, i.e. having two distinct components for these two different entities, seems more in the true spirit of how angular components are meant to be used.
I suppose one could argue that a more generic page component/view could have some valuable structure that persists for both the list view and the detail view, e.g. main title, navigation links, user info, etc. However, even if you implemented that, I think you'd want to eventually create separate (more deeply nested?) components for the whole list versus for an individual item, which eventually comes back around to implementing your latter suggestion.
I think a useful model is the example code provided on the official Angular2 web site. I could point to several different examples, but I think the clearest parallel to your situation is in the "Advanced Documentation" section, under the "Routing & Navigation" heading. There they provide code that separates components as follows:
hero-list.component: This would seem to parallel your listpage.
hero-detail.component: This would seem to parallel your detailpage.
Clearly they've separated out these two parts of the app into distinct components.
This sort of strategy decision may also depend on the size/complexity of your "entities". If your "list" and "detail" views were both extremely simple, I suppose you could distinguish between them within a single component (e.g. page), just using an attribute (e.g. type). However, in a todo app, I can't imagine either a list view or a detail view being extremely simple. Thus trying to squash both into a single page component would make the component too complex.

Should I structure the Redux store after the domain or after the app views?

I'm trying to wrap my head around Redux and how to implement it in a React Native app.
I get the general idea and I like it. But I'm not quite sure how to structure my store. I'll try to give an example with two scenes from the app.
ProjectListScreen:
A list of projects built with a ListView component. Each row exposes about 5 fields from each project object.
ProjectScreen:
A ScrollView showing all fields for a specific project. The project object can be quite large and not entirely flat. For example it holds an array of UUIDs pointing to images.
So, should I have a single reducer to handle the complete "Projects" or should I have one reducer for ProjectList and one for Projects? I.e. should I think in terms of the real domain or in terms of views/screens in the app?
I suspect that the answer will be to mimic the domain. But what if there are 1000 projects in the list? I need to load 1000 projects into the store including all fields for each project. But I will only need five of those fields to render the ListView. Only a couple of projects will probably be loaded fully because the user won't open all 1000 projects in a ProjectScreen. A change in one project will force a copy of the while array in order to stay immutable.
I don't want to get stuck in premature optimizing, but I'd like to get the structure of the store somewhat right from start. I know I could use Immutable.js to optimize the updating of items in the list, but this would give me non JS objects to work with, which feels kind of cumbersome.
I'd rather use seamless-immutable, but I don't think this kind of partial update of a large list will be faster with SI than copying the list.
I'd love to hear that performance will be a non-issue compared with the UI rendering and other tasks. This would make it a no-brainer to go with a domain structure.
Domain, absolutely. Your store structure should totally reflect the actual data you're working with. Your UI layer should then do any transformations needed on a per-component basis, primarily in your mapStateToProps functions. Focus on the actions and behavior that make up your application at its core. (This should also lead to a better testing setup as well.)
The best practice for organizing data that is nested or relational is to normalize it, similar to tables in a database. I've written some prior answers that describe this concept to some extent, and link to some further articles and discussions ( [0], [1], [2] ).
I generally advise against using Immutable.js, at least to start with. It has its uses, and can offer some performance improvements if your app is configured correctly, but also has a number of potential performance pitfalls as well ( [3] ). I would suggest sticking with plain JS objects. There's a variety of ways to use those in an immutable fashion. I have a list of articles describing those approaches ( [4] ), as well as a list of libraries that can make immutable use of plain JS objects easier ( [5] ).
Finally, I'm actually just starting to work on a new page for the Redux docs that describes best practices for structuring reducers. It'll take some time to get it written and polished, but you might want to keep an eye on it. The issue is at [6], and that has a link to my current WIP article branch.
[0] https://stackoverflow.com/a/38105182/62937
[1] https://stackoverflow.com/a/38017227/62937
[2] https://stackoverflow.com/a/37997192/62937
[3] https://github.com/markerikson/react-redux-links/blob/master/react-performance.md#immutable-data
[4] https://github.com/markerikson/react-redux-links/blob/master/immutable-data.md
[5] https://github.com/markerikson/redux-ecosystem-links/blob/master/immutable-data.md
[6] https://github.com/reactjs/redux/issues/1784
edit:
As a follow-up, the Redux docs now include a "Structuring Reducers" section, which has a variety of information on this topic.

Categories