Avoid usage of JS Map with Immutable Map - javascript

How can I avoid the confusion of native Map with Immutable.Map?
I use immutable.js in a react project (ES6 or later, transpiled with babel).
So a lot of files start with an import like:
import { Map } from 'immutable';
Everything is fine until somebody adds the above import to a file that uses native JS Map, so that new Map() becomes an Immutable.Map.
I could consequently import the whole immutable library (import Immutable from 'immutable';) and reference it using Immutable.Map. However, this has possibly impact on the size of the resulting code (the compiler is likely not able to figure out that not the whole imported lib is used) and probably does not look nice.
Are there better solutions? Can I somehow reference native JS Map specifically?

You have two options here. I like the first, but YMMV.
Native JavaScript modules allow you to alias not just entire library imports, but individual named imports: import {Map as IMap} from 'immutable';. Now there's no conflict and your bundle size should be smaller. Added bonus: the intent of your code might become more clear to future maintainers who will now immediately know they're not dealing with normal native Maps.
The actual constructor is a property of the global context: just reference window.Map which won't conflict with the one you imported into the module namespace.

I'd recommend either importing Map in your higher order component and passing it down to your component as prop or using an import alias (as proposed in #Jared Smiths answer)
HigherOrderComponent
import { Map } from 'immutable';
class HigherOrderComponent extends React.Component {
render() {
return <myChildComponent map={Map} />;
}
}
myChildComponent
class HigherOrderComponent extends React.Component {
componentDidMount () {
this.myMap = new this.props.Map();
}
render() {
// ...
}
}

Related

Memory when importing js objects in react

I am new to react and its transpiled way of generating javascript.
In react side, I have a class Utility that uses a data object UserData organized as below -
UserDataObj.js
class UserData{
this.someobj = {};
//some function here
something(){
}
}
const UserDataObj = new UserData();
export {UserDataObj};
Utility.js
import {UserDataObj} from './data/UserDataObj';
class Utility {
doSomething(){
//UserDataObj.something();
}
}
const utility = new Utility();
export {utility};
I have another ReactApp UserApp.js, that also uses UserDataObj and Utility (although not good design wise) -
import {UserDataObj} from './data/UserDataObj';
import {utility} from './Utility';
class UserApp extends React.Component{
//does something with UserDataObj
// also does somethign with utility
}
My question is, how many utility and UserDataObj instances will be created in memory, when UserApp is rendered. My guess is, it should be only 1 instance for both. But I want to confirm if importing n times creates a new instance every time.
Any good read on this topic is greatly appreciated.
Thanks
This depends on the bundling tool, and not React. I imagine that the new browser ES Module resolution scheme works in the same way.
Most bundlers that I know of, and other import schemes such as Node.js' require module resolution will cache the import between files and always return the same exported objetcs. This is a requirement for prototype inheritance, for example, otherwise, it would mess up the instanceof operator.
That exported new Utility() instance will be the same for any module that imports it. In order to generate new instances, you would have to have a function.

How to use the instance of class in another file?

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

How do you import untyped ES6 react components into a Typescript component without typing the JS child components?

If I have an ES6 component like so:
component OldThing extends React.Component {
constructor(props) {
super(props);
}
render() {
return <div>{this.props.someProp}</div>;
}
}
an ES6 container like so:
const OldThingContainer = connect(mapStateToProps, mapDispatchToProps)(OldThing);
and a new typescript component like so:
component NewThing extends React.Component<Props, State> {
render() {
return <OldThingContainer someProp={someValue} />
}
}
I currently get an IntrinsicAttributes error about someProp not existing on OldThing. How do I get rid of that error without adding types/typedefs to/for OldThing and/or OldThingContainer? I tried the #augments solution on the OldThingContainer where it's defined but that doesn't seem to help. Neither did adding the comment on the component itself.
The reason I want to be able to import JS without types is that we are adding typescript to a very large, multiple years old code base and it's currently difficult to get people to write typescript components at all, let alone if they also have to type out every existing component their component wants to import.
Is there an existing elegant solution to this problem or am I going to have to go through ahead of everyone and manually type every existing JS component (hundreds) in some typedef file to get rid of/prevent these errors?
I tried your example and it seemed some issue with the type connect inferred for your component.
One quick'n'dirty fix would be to annotate your JS component with:
/**
* #type {React.ComponentType<any>}
*/
const OldThingContainer = connect(mapStateToProps, mapDispatchToProps)(
OldThing
);
One more elegant fix (but maybe not possible) would be trying to dive into the react-redux typings. The connect function requires you to supply some type arguments for it to properly work. When not supplied, those arguments are given {}, not any (because any can silently eat your types).
Comment: From the few I've worked with react+redux+typescript, lib typedefs are one of the biggest pain points. React typedefs can get really complicated. (flow just will hang up your editor with "waiting for flow server", which is even worse). As TS+Redux gets more popular and more support is added, this may get a lot better in a few months...

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