About React, Suspense, lazyLoad and preloading/rendering elements - javascript

I am studying the <Suspense> and React.lazy() concepts, and I would like to better understand what happens in order to add some logic into an existing app.
Let's start with the definitions:
The React.lazy function lets you render a dynamic import as a regular component.
(render highlighted by me)
and
If the module containing the OtherComponent is not yet loaded by the time MyComponent renders, we must show some fallback content while we’re waiting for it to load[...]
(loaded highlighted by me)
Now, the Suspense definition uses the term load, lazy() uses render.
Let's add some code to the concept.
const ComponentOne = React.lazy(() => import("./ComponentOne"));
const ComponentTwo = React.lazy(() => import("./ComponentTwo"));
function BigBang() {
return (
<Suspense fallback={<SplashScreen/>}>
<section>
<ComponentOne/>
<ComponentTwo/>
</section>
</Suspense>
);
}
Fine. The idea is that we are lazy-loading ComponentOne and ComponentTwo.
While this process is not over, we will display SplashScreen.
THE QUESTION
Now, let's assume that I have some import to some local images into ComponentOne and ComponentTwo (I will add the code only for one, let's assume there is something similar for the other one):
import avatar from "../../img/avatar.svg";
import logo from "../../img/logo.svg";
export default class ComponentOne extends React.Component {
componentDidMount() {
console.log("ComponentOne#componentDidMount");
}
render() {
console.log("ComponentOne#render");
return (
<div style={{display: 'none'}}>
<img src={avatar}/>
<img src={logo}/>
</div>
);
}
}
Now it should be clear what I would like to ask:
Does the SplashScreen disappear when ALL the imports are loaded? In other terms, when the SplashScreen disappear, can I assume that all the images in the ComponentOne and ComponentTwo are already loaded?
This is the main question.
A secondary question (that seems related to me, but if it's not I can open another thread) is: if the answer to the previous question is "NO", what is the best strategy to be sure that the images/fonts/"api response"/"other resources" are loaded before rendering, possibly maintaining the logic because of an already existent flow? Direct fetch() to resources is not supported at the moment.

Suspense waits for the dynamically imported component file (lets say 0.js) to get fetched.
Now as soon as 0.js is loaded and starts parsing, Suspense stops showing SplashScreen and delegates control the your component. Whatever happens next is not lazy loading. It would just be like what would happen if you did a static import.
In your case, the two images would be loaded only after the SplashScreen goes away. Now if you want to preload / lazy load the images there are several ways to go ahead with that.
1) If you are using webpack, you can use url-loader to inline the images as data-uri. But beware, that this might increase your bundle size and also you lose out on browser caching of images which are usually static.
2) For svgs, you can use the inline-react-svg babel plugin which will convert the svg's to react component so that its part of your bundle (0.js). But it also has the same tradeoff mentioned above.
Hence preloading images has its own tradeoffs. There might be better alternatives such as lazy loading which can be done by easily and also React HOC can be got from several third party libaries.

Related

How to invoke Quasar dialog from external component?

I'm using Vue.js 2.x + Quasar 1.x with http-vue-loader (so no build tools) at the moment.
I put a q-dialog in a separate component - let's call it MyComponent, and when I just hook it up in a parent component like so:
<my-component></my-component>
then nothing happens, it's not even in the DOM... When I just insert the whole q-dialog template into the parent component, without having its separate external component, everything works just fine with a simple v-model.
So I imported the component successfully, that part is fine.
I was trying to invoke it when I click on a button, but I can't really communicate with the component this way.
Now I've come across two separate ways of creating dialogs in Quasar, the first one is using the component when it's not in its separate component. The second one seems to be the one I might need for a separate dialog component. The problem is that importing an external component with vue-http-loader looks like this:
components: {
'my-component': httpVueLoader('/components/MyComponent.vue'),
},
while according to the Quasar docs, it should look like this:
import CustomComponent from '..path.to.component..'
...
this.$q.dialog({
component: CustomComponent,
...
The docs are a bit confusing to me as well. :/
Unfortunately, I can't see the CustomComponent code, which is required to be created following an interface, which is described in this docpage under the warning. Make sure that CustomComponent is valid.
P.S. - Both of those ways do the same thing but in different ways. With the first one, you'll import that component to another and set him in the template, but with the second one, you'll call a tool, that creates a new modal with passed parameters. But the second one doesn't have all functionality compared to the first one.

Angular: way to know when all child components View are inited

Let's say I have the main app.component with <router-outlet/> and this component can have multiple nested components. Some of them are very lightweight, some of them have tons of component-code + a lot of DOM objects, like images etc.
It looks that when I use on my main app.component
public ngAfterViewInit(): void {
console.log('loaded: ', new Date());
}
it fires imideatly after this component's view is inited, not taking into account all nested childs (I can't hardcode ngAfterViewInit everywhere - I have more than 100 components).
Is there any good way to know when all components Views are invited in Angular?
Also is there any good way to know also when all images are loaded on current route page?
When your root component is loaded this is signal about all child component is loaded on that CD tick. With router components, you need to implement the same logic(when the root of the current route is loaded then all children are loaded).
Example link with loaded images counter, router-outlet counter and how works ViewInit
I guess not all components are loaded when you initiate app.component.ts. it's more about modules, when you hit a lazy loaded module all of its components are initiated, and so on.

Importing CSS in one component is adding CSS affect to other Components. How and Why?

I am from Angular Background and as far as I know. Each component has its own beauty and till we import a CSS file inside itthose CSS classes should not be applied even if we add to HTML Elements to the component in case we have not added or imported any CSS files for classes used inside this new/2nd component.
What I did in React was made 2 components - Home1.js and Home2.js. When I am importing a css file named Home.css to Home1 Component and NOT to Home2.js component - How in the world is those CSS classes affect being applied even too Home2 Component. This is sheer absurd.
That's why I am importing someFile.css **specifically** to the component where I want its affect to be there. This provided a kind of encapsulation affect, which I am seeing is failing. Now, someone can explain me how in the world, wherever I am not importing someFile.css, there also the classes are having affect?
Home1.js
import React, { Component } from 'react';
import './home.css';
class Home1 extends Component {
render() {
return (
<div>
<div className="red">1...</div>
<div className="green">2...</div>
<button>click</button>
</div>
)
}
}
export default Home1;
Home2.js
import React, {useState} from 'react';
const Home2 = () => {
return (
<div>
<div className="red">1..</div>
<div className="green">2...</div>
<button>click</button>
</div>
)
}
export default Home2;
Result:
Angular does it through viewEncapsulation, but this notion does not exists in react. You either need to scope your css manually by adding a main class on the top node of your component, or use a library that can do it for you (haven't tried it, you can refer to #Abdelrhman Arnos comment).
In React, like someone already had commented, you need the CSS modules to handle your problem. Actually, it's already included in the css-loader, which is a very basic module you need for webpack to handle the CSS files in the bundling process. I am not sure if you build your React app from the ground up, but I am quite sure you already had this module in your project.
{
loader: 'css-loader',
...
options: {
// Automatically enable css modules for files satisfying `/\.module\.\w+$/i` RegExp.
modules: { auto: true },
},
},
I believe you are an experienced web app programmer, and just complaining about the design of the React, but I would like to provide a little basic knowledge of browser rendering mechanism here for whom just start learning web programming and thinking about the same question.
The basic of the rendering engine in the browser is interpreting the HTML, XML documents. After loading assets by such as <script>, <style>. There are a couple of steps to complete the rendering. The step to apply CSS rules on pixels is Style calculations.
What browser does is very simple, it takes the CSS files, applies the rules, something about the scope of the styles really rely on the practice of library/framework, you can imagine that the best they can do is preprocessing the CSS files and add some unique properties to each CSS rules corresponding to the specific class names it can find in your code.
Where to import the CSS file is just for readability and maintainability. In the old times, when people still program web app with jQuery or pure JS, you just include the CSS file in the .html file, maybe it forces you to care about the naming of the classes and styles earlier, but actually we also have the same problems when you try to separate it for bigger projects.

React-router or not?

I'm currently making a react application with create-react-app
It's a single page with several sections (Home / About / Contact ...)
Each section is a component that I export, of course.
Currently my App.js is like this :
App.jsx
import Menu from './components/menu/Menu';
import Header from './components/header/Header';
import Home from './components/sections/00_home/Home';
import About from './components/sections/01_about/About';
import Works from './components/sections/02_works/Works';
import Contact from './components/sections/03_contact/Contact';
const App = () => {
return (
<div className={styles.Container}>
<Menu />
<Header />
<Home />
<About />
<Works />
<Contact />
</div>
);
};
export default App;
index.js
import React from 'react';
import ReactDOM from 'react-dom';
/* CSS */
import './index.css';
/* JSX */
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
To go from one section to another I use the anchor tag href's
For example in the home section, I have links to the other sections, same for the menu.
So far so good for me, but I'm wondering a question.
Should I use react-router? If so, why?
In which situation should I use it ?
If someone could enlighten me on that, that'd be great.
Is the way I currently code unconventional?
Ced.
From your question, perhaps you misunderstood the single-page application (SPA) theory which is the main reason for why we have to adopt React Router instead of html hrefs. A brief clear overview from quick gg is that "React Router, a dynamic, client-side routing, allows us to build a single-page web application with navigation without the page refreshing as the user navigates. React Router uses component structure to call components, which display the appropriate information."
So when you are having some shared components and you want to write less code and avoid reloads whenever user navigate around which is quite annoying then React router is a solution you need.
There are few differences in both which are quite important:
React-router: You can define the links you wanna go to and with the help of Link tag you define the URL in other components. In this situation, the Link tag will not refresh the page but instead would go onto the corresponding page but a href will refresh the page.
It might be difficult for you to pass information between components, as it is an important concept behind react.
Another would be an example, like if you are on /classes link and you go for a href tag, then it that case it will redirect you (i.e., you are using a relative path) to the /classes/teachers page, but you might want to go to /teachers URL. With the lp of Link and router, when you provide /teachers, it will redirect you to this URL
I have also started working on react and these are the points I came through.

Mount Multiple ReactJS Components into a single web page

I have multiple, reusable components on a single web page. For example, a popup, sidebar newsletter signup and a simple carousel below the content.
I'm getting the following error
'__reactInternalInstance$lvoo7hroqz' of null
After some research I believe this is down to having multiple calls to react, which makes sense. Every component imports React I believe this is due to the fact react adds id's to each node and it conflicts on each instance that's called.
My question is how would I render multiple components on a single web page? when there's no parent node/container and these elements are called individually throughout the site.
Thanks
EDIT
I have three components that look similar to below.
import React, { Component } from 'react'
export default class test extends Component {
render(){
return (<h1>test one</h1>)
}
These three individual components appear randomly around my page.
<div>
<header>
Some HTML/PHP here
<ReactTestComponent />
</header>
<div>
content here
<AnotherComponent />
</div>
<FinalComponent/>
</div>
These three components do not always appear on the same page, for instance "FinalComponent" may be missing from the next page (depending if you're on a archive page etc) so all my components need "import React from 'react'" at the top of each file.
When I render multiple components on a single page. I get the following errors. (Based on the amount of components rendered, if I render two components I get two of the same error)
Uncaught TypeError: Cannot read property '__reactInternalInstance$lvoo7hroqz' of null
at Object.getClosestInstanceFromNode (react.min.js:504)
at findParent (react.min.js:36970)
at handleTopLevelImpl (react.min.js:36999)
at ReactDefaultBatchingStrategyTransaction.perform (react.min.js:6065)
at Object.batchedUpdates (react.min.js:36768)
at Object.batchedUpdates (react.min.js:1779)
at dispatchEvent (react.min.js:37079)
OK, looking into this a little further I noticed it was a error on my part.
One of the includes was calling the same react file in addition to the footer, so I had two referenced to react.min.js causing the conflict.
Hope this helps someone.

Categories

Resources