Dynamically adding routes and components in Mithril - javascript

Mithril's website states:
You can only have one m.route call per application.
So I was almost able to do a work around with code splitting.
But my application is only aware of the first-level components for a given URL which it utilizes the async code splitting to accomplish.
Now the problem: Those first-level components would then like to register their own namespaced routes to leverage URL state change for their own inner components since I can't register their routes ahead of time (and Mithril prevents setting the routes again after the initial route was set by the app/wrapping component).
To further the complexity of the issue, each first level component is loaded on an as-needed basis, so I can't wait for all the first level components to load and then instantiate the m.route; routes have to be added dynamically.
I love this framework, but my use case seems like an edge case that I can't seem to resolve.
The simple solution would be to re-instantiate the m.route object after each first-level component loads, but that's not supported.
UPDATE
The purpose of my post was to find a native way to do dynamic routing and not lose functionality (such as variadic routing), but its been reinforced that that's not possible.
I replaced the entire router with an in-house one so I could support dynamic (and unknown) routes, more flexible variadic routing, better params method, and even provide get/set global data across views without a global window variable or use of the History API in that case. I still provide the rest of the functionality that Mithril does, just a little more simply.
Why not do a pull request? From what I've read on different Github pages, two big pieces of this would not work with the core logic of Mithril; and/or, is too much of an edge-case that they don't want to support it.
I'll still choose Mithril over any other framework though.
In the meantime, I built what I need, and hope Mithril 2 will have dynamic routing baked in.

Mithril's router is intended as a relatively simple solution to easily enable standing up simple SPAs, dynamically registering routes isn't part of the current design.
I think you'll probably be best served by finding a router that supports the dynamic route registration you require and using that.
Integration of that router with Mithril could be naive (using m.mount() when routes change) or more complex by emulating a bit of the logic of the existing router API.

Mithril's router is not the most advanced tool. Although you can work around it pretty much however you want.
There is a way to make new routes dynamic.
I made a little jsfiddle a while ago. https://jsfiddle.net/Godje/cpzLtoyz/
You are interested in lines 2-11 and 63-92.
Although they aren't dynamic in the fiddle, you can make a function, to replace that switch on line 73, which will process your routes and return a component needed to be rendered. That way if you have an array stream with all the URLs or other routes you want, you can have a function process each param on each route-change call and check it with the array.
Sorry for a messy response. Writing an exact solution to the problem requires a local server.

Related

React - Scalable architecture without Redux (MVC + DDD approach)

Introduction
React is really flexible, it seems that we are not forced to follow a specific architecture when programming interfaces, unlike with other libraries, it is something like coding a plain view. With small web apps, this is cool, but... as soon as your app starts to grow, the speed with which you code will decrease progressively, contrary to if you had defined your architecture from the beginning of the principles.
My Architecture
In my case, I am not using Redux for state management... instead, I am using React Context + React Hooks.
This is my current project structure (serverless app built using firebase):
/app
/components
/Activity
/Authentication
/Profile
/Buttons
/Text
/Inputs
/Giphy
/Messaging
/HOCs
...
/screens
/Activity
/Authentication
/Profile
/Messaging
...
/contexts
/Users
/Content
/Auth
...
/hooks
/auth
/profile
/users
/content
/badges
/i18n
...
/navigation
/Stacks
/Tabs
...
/services
/third-party
/firebase
/api
...
/lib
/theme
/styles
/utils
/functions (backend)
As you can notice, I am using some kind of domain-driven design to structure my project files.
Also, I am separating concerns from screens and components using hooks, and managing complex state (or which need to be synchronized between routes) inside contexts that contains the respective reducers.
This seems to me like some kind of MVC. Where the View is composed by all my React Functional Components, the controller is composed by all my Business and UI hooks, and the data of my Model is contained inside Contexts (or, at least the dynamic data, because of efficient reasons).
As you can see, I have a folder "services" which is just the interface that my business hooks use in order to connect to my server (cloud functions).
Questions
Does this architecture have a name (flux/redux??)? I mean, with the passage of time as a React programmer, mistake after mistake, I have ended up organizing my projects like this, in a "natural" way.
Is it an anti-pattern to split all my components logic with hooks? I mean, all the functional components of my project just contain the event handlers or the JSX to render the UI. I have moved every single block of code to hooks, some of them contain the logic of my business, others simply complex logic related to the graphical interface (animations, ...)
Which advices do you give to me in order to refine my current architecture?
useSelector with React Context? I have implemented some custom hooks that just read and compute derived data from contexts... as I can't use "useSelector", I don't know if this is something typical, because they just consume the necessary contexts (useContext) and then execute some calculations.
Is it Redux really necessary? For a medium-large project, I have handled it well using React Context and with the help of the hooks my code has been quite clean. Do you think that over time, as the project continues to grow, it will be necessary to move to Redux?
Are react hooks the controllers of an application?
Well, not completely sure that this is the right place to put questions like this, but let try to answer, from my point of view, to these points.
Answers
I don't think this specific architecture has a name (like, for example, this one, that has a name https://www.freecodecamp.org/news/scaling-your-redux-app-with-ducks-6115955638be/). In any case the name would not be "Flux" or "Redux" since these names are more related to how data is treated instead of how folders are structured in the project. I don't think there is some strict rule about folder hierarchy to follow to be fully compliant with Flux or Redux patterns. For sure there are best practices and conventions, but they are not mandatory.
To answer this point, let me share this link https://medium.com/#dan_abramov/smart-and-dumb-components-7ca2f9a7c7d0 about an article posted by Dan Abramov. I am sharing this article because of the last update made (the article is dated 2015, but there is an important update made in 2019). As you can see seems that you are doing it good since you are putting the core logic in hooks. Just a note about this point: you said "functional components" but I think you were referring to "presentation components", this is an important distinction because "functional component" means that your component is based on a function (instead of a class), "presentation component" instead means that the component does not contain business logic. A "presentation component" can be both class-based or functional and a functional component can contain business logic (class-based component are being replaced by functional ones, but this is another story).
Some advice: be coherent with capitalization and casing (you are mixing uppercase and lowercase, dash-case and camelCase, usually I like to name every file or folder in dash-case, but it depends on you); nut sure if HOCs folder should be here; maybe you can put all the utils (lib, theme, styles and utils itself) in a directory called utils where each util is named property;
About context, and this is a controversial topic, just want to share some considerations taken from docs https://reactjs.org/docs/context.html#before-you-use-context and share my opinion on that. The idea behind context is "Context provides a way to pass data through the component tree without having to pass props down manually at every level", as per documentation subtitle. So, basically, it si something created to avoid "property drilling", as exposed here https://medium.com/swlh/avoid-prop-drilling-with-react-context-a00392ee3d8 for example. This is just a personal point of view but, maybe, is better to introduce Redux for global state management instead of using Context API.
Don't be scared to use Redux. Be scared if, while using Redux, you have tons of duplicated lines of code. In this case you should think about how to abstract your actions and reducers (for example with action creators). If you will be able to generalize stuff like "getting a list of items from your backend", you will realize that your code will not just have less lines of code than a repetitive one, but it is even more readable and coherent. For lists, for example, you may have an action like const getListOfNews = list("NEWS_LIST", "/api/news/"); where list is an action creator like const list = (resource, url) => (params = {}) => dispatch => { // your implementation... };, something similar with reducers.
No, they just "let you use state and other React features without writing a class" as said here https://reactjs.org/docs/hooks-intro.html from docs. It is important to avoid trying to adapt a pattern like MVC to something that was created with different ideas, and this is a general advice. Is like if you are coming from Angular and you try to work in the same way in React. Basically you should work with React, or other libraries/frameworks, without trying to transform them from what they are to what you already know.

Using Vue events or Vuex to pass data between components (performance)?

I'm working on an application that needs to share information from one component and another component which uses that information to update a canvas element at 30-60fps. I'm targeting low end devices, so performance is important.
I'm currently using Vuex store/get to transfer information between the two components. While it wouldn't be as clean, I realized I could also use events to pass this information up and back down the chain.
I've had a hard time finding performance information on Vuex, so before I go re-writing a significant part of my code I figured I would ask here.
I don't know if it matters, but I am currently calling the getters from an ES6 module.
Is your app big?
I personally avoid Vuex as long as I can. The trouble with it is that if your Store gets big, it becomes a big Object, always available for you. On every page, every subpage, every Component etc. it is loaded. Which means it takes Browser's memory.
There is a trick to use Subscribe and Unsubscribe Vuex methods to add and remove Vuex modules, and use them only when they are necessary. But still they are a "global" Object.
If you really need to use Vuex try keeping it as small as you can. Don't put everything in it.
I havn't test it but I am sure props and $emits will work quicker then mutations and getters.

Proper way of non-blocking load of unrelated models for nested route in Ember

My routes look roughly like this:
```
/
/sites
/:site_id
/settings
/user-defined-params
/:param_id
```
Now in /user-defined-params I want to display table-list of parameters assigned to that given site. The models are not related, I mean site doesn't have collection of params as a relation, so I can't simply fetch them via this relation.
Should model() hook for my router return list of these params? By default the model seems to be site loaded from parent route (:site_id). What if loading takes some time and I'd like to actually display this table (so do actual transition) but then show kind of loading indicator waiting for table to fill in with the data.
When I try to load this in model() hook, transition blocks. When I try to load it in afterModel() hook, I don't have a way to assign it and make it available for template (other than force-assigning params property to site model, which seems to be wrong).
All the examples I've found over the Internet seem to be lacking this scenario, which I feel is one of the basic ones, so any hints on that? How should I load it (ideally without blocking transition)?
The defaults in Ember's current router (as you have found) are to block UI loading completely until the promised returned in model hooks have resolved. However, there's interest in adjusting that so we can easily build non-blocking UI patterns with the built-in router.
Right now, the community consensus here is to use ember-concurrency and it's derived state (specifically the .isRunning aspect of tasks) to toggle between a loading state and a screen with the data rendered. It isn't a coincidence that ember-concurrency was built by the guy behind the first router and the current router re-think that is in-process.
One example of an approach to this is outlined here:
https://emberway.io/skeleton-screen-loading-in-ember-js-2f7ac2384d63
I personally prefer to use my route to do the initial task loading and the consume the data in the template. But in a more complex UI I also will go with container components as outlined in that article.

Pass language as a dynamic property from parent component to all descendants in React

I'm creating multi language app. So I'd like to propagate language property to all descendants. Thus I can ad language prefix to all links and routes in my app
I know two ways to do it:
using context, but it is not recommended to use it, because it is experimental.
using redux store but in this case I need to connect every component to store.
So I wish to know which case is more preferable or if none of those, then may be there is another option.
P.S.
3. pass as a property from component to every child all the levels deep, like this:
<Component1 lang={props.lang} />
<Component2 lang={props.lang} />
<Component3 lang={props.lang} />
<Component4 lang={props.lang} />
....
<Component#N lang={props.lang} />
Here are my thoughts and solutions that work the best for me.
Handling internationalization logic is not really the job of the component. Generating links at that level is coupling component too much to the app and makes reuse of them complicated. I have done it in the past and it was a nightmare to maintain. Not even translation related things, think about changing URL for some view when you have generated links to it from different places of your app. I consider it now bad practice and not recommend for anything bigger than TODO app.
Now I'm using separate service which handles dynamically generation of links and routes based on app configuration/internationalization.
That service is exposed as a global in Webpack configuration as let's say LocationPointer. So for example:
LocationPoiner.admin()
will return string pointing to admin view based on an active language (/en/admin-panel).
I don't treat language as a changeable state. For SEO and UX reasons, what I want is internationalization based on a shareable URL, which is the single source of truth.
If you are on SPA and change language by clicking button etc. then the whole app is forced to completely refresh.
During page loading, I detect language, save its value somewhere and pull correct translations.
Note - My backend is using internationalization as well, so when a user changes the language, some requests have to be done again in order to display correct data. It's not just refreshing front-end components. And is worth to remember about it. When your app grows it will probably also respond with different messages/data depending on internationalization.
My pulled front-end translations are stored in another service and exposed as a global through Webpack as __(), which returns translated string.
So if I want Link in my React component I will do:
<Link to={LocationPointer.admin()}>{__('Admin')}</Link>
Passing language as a prop makes sense to me when you use multiple languages on a single page at the same moment. Otherwise, in my opinion - it just creates a mess.

Best practice for node - mongo - angular

I have an app I am designing using node/mongo/angular, what I am not getting is how is the best way to get my data from mongo into my pages? I can use node, and thru my routes send back data from mongo with my template(hogan in this case), and bind using mustachejs. That works fine for most things. I have one screen that has a decent amount of drop down lists, to bind them for an edit scenario now seems a challenge. I would like to get them bound to an angular model and go about it that way. Is it better to get the data thru the route in node, then use something like ng-init and get it into angular? Or would I be better off not getting the data thru the route in node, and then using angular to perform a "get" request and bind that way?
From the documentation of ng-init, more precisely from the red warning alert at the top of the page...:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
So no, do not use ng-init. While that can be a good strategy for lazy migrations from regular applications to single page applications, it's a bad idea from an architectural point of view.
Most importantly, you lose two things:
An API. The benefit of SPAs is that you have an API and that you're constantly developing and maintaining it, even before it has external users
A clean separation of concerns. Views are strictly limited to presentation, can be cached by the client and all data is transferred through JSON API endpoints.
I would say that the best way to get data from Mongo into your page, is as mnemosyn said, using an API.
Basicly, you can have your API route, f.ex '/api/data' configured and then it can be used by a angular service, (which can use ngResource to make things easier). Any controller that wishes to access this data can use the angular service to get it, do some stuff with it, and then update it using the same angular service.

Categories