How to use the instance of class in another file? - javascript

I am using babylonjs in my React app. Since this file get bigger and bigger I try to split it into several parts.
Scene3d.js
import * as Setup from './Scene3d/setup'
class Scene3d extends Component {
...
}
export default Scene3d
setup.js
import Scene3d from '../Scene3d'
Unfortuantely I am not able to use the instance object of Scene3d. Scene3d just returns the component in setup.js. I want to avoid to add "this" to all function to pass the object to the functions.
I appreaciate your help.
Best

Related

How are the imports implemented in different React libraries and how can I implement the same pattern in my own library?

For example, the recommended way of importing in React Bootstrap is to go this way:
import Button from 'react-bootstrap/Button' instead of import { Button } from 'react-bootstrap';
The reason is "Doing so pulls in only the specific components that you use, which can significantly reduce the amount of code you end up sending to the client."
source: https://react-bootstrap.github.io/getting-started/introduction/
Same for React MUI components:
import Button from '#mui/material/Button';
source: https://mui.com/material-ui/getting-started/usage/
I want to implement something similar in my React components library, to limit the usage of code in the bundle, but I don't know how they implement this specific pattern. I have looked at their code base, but I don't quite understand.
Basically it is all about modules and module files and their organization. You can have a lot of.. lets call them folders, "compoments/*" for example. "components/button", "components/alert", "component/badge", and other things. All of them will have some index.js or .ts file that will export or declare and export all the functionality that needed in order to make this component work, 'react-bootstrap/Button' for example. Ideally all those subfolders or submodules are independend from each other, no references between them but probably each one will have 1 reference to 1 common/shared submodule like "components/common" which will contain some constants, for example, and no references to other files. At the top level of them you will have another index.js or .ts file that is referencing all of those components, so "components/index.js" will import and reexport all the nested components index files. So in order to import a Button, for example, you can either import "components/index.js" file with all the other imports this file is using, either only 1 single "components/button/index.js" file which is obviously much more easy to fetch. Just imagine a tree data structure, you import root of the tree (root index.js) - you get all the tree nodes. You import one specific Node (components/button/index.js) of the tree - just load all the childs (imports) of that node.
Sorry for a long read but asuming you mentioned webpack - there is a technique called tree-shaking which will cut off all the unused things.
Info about modules: https://www.w3schools.com/js/js_modules.asp
Info about Tree-Shaking: https://webpack.js.org/guides/tree-shaking/
It might not be as complicated as you think. Let's say you write the following library:
// your-library.js
const A = 22
const B = 33
export function getA () { return A }
export function getB () { return B }
export function APlusB () { return A + B }
// a lot of other stuff here
If some consumer of your library wants to make use of the APlusB function, they must do the following:
// their-website.js
import { APlusB } from 'your-library'
const C = APlusB()
However, depending on how the code is bundled, they may or may not wind up with the entire your-library file in their web bundle. Modern bundling tools like Webpack may provide tree shaking to eliminate dead code, but this should be considered an additional optimization that the API consumer can opt into rather than a core behavior of the import spec.
To make your library more flexible, you can split up independent functions or chunks of functionality into their own files while still providing a full bundle for users who prefer that option. For example:
// your-library/constants.js
export const A = 22
export const B = 33
// your-library/aplusb.js
import { A, B } from 'constants'
export default function APlusB () { return A + B }
// your-library/index.js
// instead of declaring everything in one file, export it from each module
export * from 'constants'
export { default as APlusB } from 'aplusb'
// more exports here
For distribution purposes you can package your library like so:
your-library
|__aplusb.js
|__constants.js
|__index.js
You mentioned react-bootstrap and you can see this exact pattern in their file structure:
https://github.com/react-bootstrap/react-bootstrap/tree/master/src
and you can see they aggregate and re-export modules in their index file here:
https://github.com/react-bootstrap/react-bootstrap/blob/master/src/index.tsx
Essentially, what you are asking is:
"How to export react components"
OR
"How are react components exported to be able to use it in a different react project ?"
Now coming to your actual question:
import Button from 'react-bootstrap/Button' instead of import { Button } from 'react-bootstrap';
The reason is 'Button' component is the default export of that file react-bootstrap/Button.tsx. So there is no need for destructuring a specific component.
If you export multiple components/ functions out of a file, only 1 of them can be a default export.
If you have only 1 export in a file you can make it the default export.
Consider the file project/elements.js
export default function Button(){
// Implementation of custom button component
}
export function Link(){
// Implementation of custom Link component
}
function Image(){
// Implementation of custom Image component
}
Notice that the Button component has 'default' as a keyword and the Link component doesn't.
The Image component can't even be imported and can only be used by other functions/components in the same file.
Now in project/index.js
import 'Button', {Link} from './elements.js'
As Button component is the default export its possible to import without destructuring and as Link component is a regular export, I have to destructure it for importing.

Is an explicit export necessary when a function is made available from an index file?

I use vanilla JavaScript to define various components in separate folders. For example, the definition for the accordion component can be found in accordion/accordion.js and is structured as follows:
import toggleCollapsible from "../../helpers/toggle-collapsible";
const SELECTOR_ACCORDION = ".accordion";
const SELECTOR_SLAT = ".accordion-slat";
function Accordion(accordion) {
...
}
Array.from(document.querySelectorAll(SELECTOR_ACCORDION)).forEach((accordion) => Accordion(accordion));
export default Accordion;
There is also an index.js file which is used only for making the component available elsewhere via export * from "./accordion";
Leaving out export default Accordion; part in accordion.js seems to work just fine. So is there any reason why I shouldn't drop it and simply use just export * from "./accordion"; in the index file?
If you don't export anything from the module, then export * from ... will also export nothing.
However, just importing that module has that side effect of activating the array for elements on the page, which feels unclean (and indeed, might not work if the script is in <head>, for instance...).
I'd wrap the Array.from() stuff in a function that's exported:
export function activateAccordions() {
Array.from(...);
}
and then import and call that in your index.
import {activateAccordions} from "./accordion";
activateAccordions(); // TODO: might need to call this only after the page is loaded
Then, if you additionally need to be able to accordion something arbitrary,
export function Accordion()
and import it too...

Are multiple objects being created?

I'm working on a simple React library but I'm unsure whether multiple objects are being created unnecessarily.
I have an app.js file:
class App {
method1() {
}
method2() {
}
}
export default new App();
I also have an index.js file:
import app from './app.js';
...
export default app;
In the index.js of my React project (where I make use of the library) I use:
import MyLibrary from 'react-library';
...
MyLibrary.method1();
and then I do the same in some of my components too:
import MyLibrary from 'react-library';
...
MyLibrary.method2();
Is the second import of MyLibrary a different object to the first MyLibrary?
Is the second import of MyLibrary a different object to the first
MyLibrary?
In general the object returned by the import is cached (same behaviour as nodejs require), multiples import of the same file will result in the same object being returned. So the answer to your question is No, you're dealing with the same reference in memory.
https://webpack.github.io/docs/resolving.html
Every filesystem access is cached so that multiple parallel or serial
requests to the same resource are merged
in your particular case, as suggested in the comments section, you're exporting an instance, not the class itself.
export default new App();
consequently each component that import that file will deal with the same instance.
This is a singleton pattern, don't know if it is the desired behaviour, if you want that each component has it's own instance you should export the class instead.
export default App;
You are creating a singgleton there, put a breakpoint in the constructor and you will see how only one instance is created.

What is the benefit importing React, {Component} instead of just React?

What is the major benefit of writing
import React, { Component } from 'react';
class Link extends Component {
...
}
instead of
import React from 'react';
class Link extends React.Component {
...
}
when it comes to react 15.4.x??
In my perspective and in my case (correct me if I am wrong) it does not matter at all since:
I am using a webpack2 for making my bundles;
I use code splitting to split my app code from vendor code;
I use webpack.optimize.CommonsChunkPlugin plugin with minChunks: Infinity setting to make sure that all vendor code is included only once.
From understanding how ES6 imports work I understand that by using named import of {Component} I state that I want to use only Component component in my code, which looks.. cleaner.
But since whole React package is still used in the app, I can create my classes with extension from React.Component instead of just Component and in result webpack will still produce the same amount of code and my bundle size will be the same in both cases.
Am I correct?
There is no difference, React.Component is the same object as Component, the second way is more eloquent in my opinion, because it really explains that you are using the Component object from the React library.
The first one seems to refer a member,
but, it comes from the pre modules era of javascript, where everything had to be attached to the exported global namespace (just to avoid global namespace pollution).
something that could be under the hood:
// this should be assumed as an example only.
class React { ... }
class Component { ... }
React.Component = Component;
// ES6
export {Component}
export default React;
// ES5
window.React = React;
Note: as someone said, you also need to import React because JSX needs to have it on scope, but, if you want to avoid it, you can expose React globally (window.React = React)
This import statement:
import React, { Component } from 'react';
is really doing two things. It imports the default export, under the name React (which is just a convention, you could call it what you want). It also imports a named export, Component.
The reason that the default React is imported is actually to make JSX work. When your JSX code is transpiled, then it substitutes <div> for React.DOM.div(), so React must exist otherwise things break!
Importing both things separately means that your JSX works but you get to write Component instead of React.Component in your code.
When you do import anything from "react", then the whole file is going to get included either way - any attempt to reduce the bundle size (e.g. Dead Code Elimination, Tree Shaking) is an additional, separate step, which doesn't depend on your import statements but the parts of the code that you use.
In the case of this library, the sane thing happens: the child Component of the default export refers to the same thing as the named export Component.
However, bear in mind that this isn't guaranteed to be the case! If the React library code contained the following:
export default {
Component: "foo"
};
export const Component = "bar";
Then React.Component === "foo" and Component === "bar".

Does importing the default export along with a named export load the module twice?

What happens when you write an import statement in the following form:
import React, { Component } from 'react';
Is destructuring of the import module occurring as in destructuring an object to achieve Component instead of needing React.Component? Or is it importing with a named export with completely differing syntax, though it does resemble destructuring?
An important corollary question: does import React, { Component } ... needlessly load up the Component object from the React module twice as compared to simply import React ... (given that Component is a constituent of the larger React library)?
To answer your first question:
No, it's not object destructuring. The syntax may have been set up that way to relate but there's no confirmation that they were intentionally made to be related. Per the ECMAScript 2015 Language Specification:
Section 15.2.2 Imports
Syntax
[...]
ImportClause :
[...]
ImportedDefaultBinding , NamedImports
[...]
NamedImports :
{ }
{ ImportsList }
{ ImportsList , }
It's completely separate syntax.
To answer your second question:
Yes, it imports it twice, once React for access as React.Component by the default export, and once as Component as a named export. Per the specification:
Section 12.2.2 Static Semantics: BoundNames
[...]
ImportClause : ImportedDefaultBinding , NamedImports
Let names be the BoundNames of ImportedDefaultBinding.
Append to names the elements of the BoundNames of NamedImports.
Return names.
As you can see, the names you import with import React, { Component } are bound twice, meaning you get React as the default export and thus React.Component, and then the bound name Component is also appended to your imported names. You essentially get it twice under two different bindings or names.
It should be noted that only the bound names are different. React.Component and Component refer the same object, just with different bindings because you imported using named exports. Once you import React, React.Component has already been imported. All { Component } does is create a new binding to the already imported object.
There is no destructuring happening in the import syntax. Even though it looks somewhat similar - it's a separated syntax.
The imported identifiers are bindings to the objects created during module initialisation. So practically you get 2 bindings to the same object, which costs you 1 extra reference, nothing more.
No matter how many times in your source code tree you import a module it would only be initialised once, with all the values created just once. And all the import statements would essentially "bind" to the values in memory without creating duplicates.

Categories