Is `import { useState } from 'react'` kind of destructure or not? - javascript

I'd like to make clear one thing.
In React, we often use import {useState, useEffect} from 'react'.
Can we think of this as a destructuring feature in ES6?

Nope.
It's not like object destructuring but it is actually importing named exports.
To be more clear, it's just importing a module exported as useState.

No, they are different.
While they look similar (and probably import was designed to look like destructuring), they don't behave the same way. To set that clear, importing uses a slightly different syntax: uses the as keyword for import renaming instead of the : familiar from destructuring.
These differences are because of how the module system works. Other differences are:
imported variables cannot be assigned to by the importer module, however...
the exported variables can be changed anytime by the exporter, and that will also be reflected by the importers' variables, and that implies, that...
it's not possible to nest import renaming, like how it would be possible via destructuring:
import {foo as {bar as baz}} from './module';
//is invalid, as is:
import {foo as {bar: baz}} from './module';
//...while:
const {foo: {bar: baz}} = value;
//is valid.
as the module system is static (like variables), it's not possible to import a dynamic key or use the rest syntax (all imports are known before evaluating the code).

Looking at react src code
export {
useState,
// ...
Children,
// ....
} from './src/React';
so you can import directly from this object e.g.
import { useState } from 'react'
// you can also rename it to anything you want
import { useState as useReactState } from 'react'
or you can get the whole object as exported as default and then reference its useState
import React from 'react'
// use React.useState
// renaming will be like assigning a function to another variable e.g.
const useReactState = React.useState
// you also get all exported types and modules and wrap them up in React name
import * as React from 'react'
Babel transpiled outputs
import React from 'react'
const Component = () => {
const [state, setState] = React.useState()
}
// will transpile to something like
var Component = function Component() {
var _React$useState = _react["default"].useState(),
_React$useState2 = _slicedToArray(_React$useState, 2),
state = _React$useState2[0],
setState = _React$useState2[1];
};
On the other hand
import {useState} from 'react'
const Component = () => {
const [state, setState] = useState()
}
// will transpile to something like
var Component = function Component() {
var _useState = (0, _react.useState)(),
_useState2 = _slicedToArray(_useState, 2),
state = _useState2[0],
setState = _useState2[1];
};
There are some similarities between object destruction and import/export statement, but they are not the same at the end both have their own specific features different with the other
ES6 in-depth |
Export Statement |
Import Statement

Related

Having problem with import in ES6 module: property is not exported

I'm currently working with redux, and I'm exporting an object with the type properties to my reducer file.
My types.js file:
const Types = {LOG_IN:'LOG_IN',REGISTER:'REGISTER'};
export default Types;
My reducer.js file:
import {LOG_IN,REGISTER} from './types';
//CODE HERE
When I compile, however, CRA give me an error:
Attempted import error: 'LOG_IN' is not exported from './types'.
Curiously enough, this code works:
import Types from './types';
const {LOG_IN,REGISTER} = Types;
Why is it that my code structure doesn't work with that form of importing while React's and Redux's code does? Thank you in advance.
You need to explicitly define a named export for each constant for that to work.
export const LOG_IN = 'LOG_IN';
export const REGISTER = 'REGISTER';
Importing a named export is not the same thing as destructuring a default export, which is what's happening when you do this:
import Types from './types';
const {LOG_IN,REGISTER} = Types;
You can read more on this here. Other code you find in the wild might appear to work like you describe because it's actually defining its exports like this:
module.exports = {
LOG_IN: 'LOG_IN'
}
I think is because you export Types, if tou can use LOG_IN for example you need to access Types.LOG_IN, and the code const {LOG_IN,REGISTER} = Types; works because you are using destructuring
the
import Types from './types';
are correct
an then try to access with Types.REGISTER

Accessing MobX store in vanilla ES6 Javascript class

This one is piece of cake in React. If you want your MobX store to be available in any React component, you just use mobx-react #inject component. Something like:
import React from 'react';
import {inject} from 'mobx-react';
#inject('myStore')
class Dummy extends React.Component {
Then, my store is available as a prop:
this.props.myStore.myMethod();
Nice, convenient... and React only. Maybe I'm missing something, but I can't find a way to access my store from a plain ES6 class. How do I get the same result in a plain ES6 class in pure Vanilla Javascript?
Answer found in MobX GitHub account by adonis-work. Quoting the answer:
Exporting store as a singleton:
// Store.js
import { observable, computed } from 'mobx'
class Store {
#observable numClicks = 0
#computed get oddOrEven() {
return this.numClicks % 2 === 0 ? 'even' : 'odd'
}
}
const store = new Store()
export default store
... enables us to import and use the active store anywhere in the app as many times we want.
// Component.jsx
import store from Store
// use the global store in any component without passing it
// down through the chain of props from the root node
store.numClicks = 4
console.log(store.oddOrEven)
I am using this approach without problems for some time now. Are there any caveats I should look out for?
Link to source: https://github.com/mobxjs/mobx/issues/605
You forgot your code starts with:
import { Store } from "./store";
import { Provider } from "mobx-react";
import * as React from "react";
import { render } from "react-dom";
var store = new Store();
render(
<Provider {...stores}>
<Component />
</Provider>,
document.getElementById('root'),
);
Here you have your store variable and you can use it anywhere
If you'd like it even more convenient turn your store into a Singleton
than you can just import it anywhere like:
import { Store, instance } from "./store";
//in store.ts/js
export Store... =
export const instance = new Store(); // your singleton
how it works
the <Provider/> react component puts the Store in its react Context, read here more: https://reactjs.org/docs/context.html.
this means the store is in every child react component of <Provider/>.
Inject just simply copies this: this.props.store = this.context.mobx.store.
Thus making a singleton and using this singleton in your 'plain' javascript class (no react subclass/component), is the same thing.

Import object contained in another object

I want to do something like this, but using import rather than require:
const MySubmodule = require('react-native').MyModule.MySubmodule;
I tried:
import { MySubmodule } from 'react-native/MyModule';
import { MySubmodule } from ('react-native').MyModule;
import { MySubmodule } from 'react-native'.MyModule;
None of these works.
So any idea how to import a module contained in another using import?
You will have to import MyModule completely, and can then separately destructure it to get the parts you are interested in:
import {MyModule} from 'react-native';
const {MySubmodule} = MyModule;
The import statement does not support directly destructuring exports. See also this Babel issue for some more info.

What is the difference between " import {foo} form './foo' " and " import foo form './foo' " [duplicate]

It seems to be obvious, but I found myself a bit confused about when to use curly braces for importing a single module in ES6. For example, in the React-Native project I am working on, I have the following file and its content:
File initialState.js
var initialState = {
todo: {
todos: [
{id: 1, task: 'Finish Coding', completed: false},
{id: 2, task: 'Do Laundry', completed: false},
{id: 2, task: 'Shopping Groceries', completed: false},
]
}
};
export default initialState;
In the TodoReducer.js, I have to import it without curly braces:
import initialState from './todoInitialState';
If I enclose the initialState in curly braces, I get the following error for the following line of code:
Cannot read property todo of undefined
File TodoReducer.js:
export default function todos(state = initialState.todo, action) {
// ...
}
Similar errors also happen to my components with the curly braces. I was wondering when I should use curly braces for a single import, because obviously, when importing multiple component/modules, you have to enclose them in curly braces, which I know.
The Stack Overflow post at here does not answer my question, instead I am asking when I should or should not use curly braces for importing a single module, or I should never use curly braces for importing a single module in ES6 (this is apparently not the case, as I have seen single import with curly braces required).
This is a default import:
// B.js
import A from './A'
It only works if A has the default export:
// A.js
export default 42
In this case it doesn’t matter what name you assign to it when importing:
// B.js
import A from './A'
import MyA from './A'
import Something from './A'
Because it will always resolve to whatever is the default export of A.
This is a named import called A:
import { A } from './A'
It only works if A contains a named export called A:
export const A = 42
In this case the name matters because you’re importing a specific thing by its export name:
// B.js
import { A } from './A'
import { myA } from './A' // Doesn't work!
import { Something } from './A' // Doesn't work!
To make these work, you would add a corresponding named export to A:
// A.js
export const A = 42
export const myA = 43
export const Something = 44
A module can only have one default export, but as many named exports as you'd like (zero, one, two, or many). You can import them all together:
// B.js
import A, { myA, Something } from './A'
Here, we import the default export as A, and named exports called myA and Something, respectively.
// A.js
export default 42
export const myA = 43
export const Something = 44
We can also assign them all different names when importing:
// B.js
import X, { myA as myX, Something as XSomething } from './A'
The default exports tend to be used for whatever you normally expect to get from the module. The named exports tend to be used for utilities that might be handy, but aren’t always necessary. However it is up to you to choose how to export things: for example, a module might have no default export at all.
This is a great guide to ES modules, explaining the difference between default and named exports.
I would say there is also a starred notation for the import ES6 keyword worth mentioning.
If you try to console log Mix:
import * as Mix from "./A";
console.log(Mix);
You will get:
When should I use curly braces for ES6 import?
The brackets are golden when you need only specific components from the module, which makes smaller footprints for bundlers like webpack.
Dan Abramov's answer explains about the default exports and named exports.
Which to use?
Quoting David Herman:
ECMAScript 6 favors the single/default export style, and gives the sweetest syntax to importing the default. Importing named exports can and even should be slightly less concise.
However, in TypeScript named export is favored because of refactoring. Example, if you default export a class and rename it, the class name will change only in that file and not in the other references, with named exports class name will be renamed in all the references.
Named exports is also preferred for utilities.
Overall use whatever you prefer.
Additional
Default export is actually a named export with name default, so default export can be imported as:
import {default as Sample} from '../Sample.js';
If you think of import as just syntax sugar for Node.js modules, objects, and destructuring, I find it's pretty intuitive.
// bar.js
module = {};
module.exports = {
functionA: () => {},
functionB: ()=> {}
};
// Really all that is is this:
var module = {
exports: {
functionA, functionB
}
};
// Then, over in foo.js
// The whole exported object:
var fump = require('./bar.js'); //= { functionA, functionB }
// Or
import fump from './bar' // The same thing - object functionA and functionB properties
// Just one property of the object
var fump = require('./bar.js').functionA;
// Same as this, right?
var fump = { functionA, functionB }.functionA;
// And if we use ES6 destructuring:
var { functionA } = { functionA, functionB };
// We get same result
// So, in import syntax:
import { functionA } from './bar';
Summary ES6 modules:
Exports:
You have two types of exports:
Named exports
Default exports, a maximum one per module
Syntax:
// Module A
export const importantData_1 = 1;
export const importantData_2 = 2;
export default function foo () {}
Imports:
The type of export (i.e., named or default exports) affects how to import something:
For a named export we have to use curly braces and the exact name as the declaration (i.e. variable, function, or class) which was exported.
For a default export we can choose the name.
Syntax:
// Module B, imports from module A which is located in the same directory
import { importantData_1 , importantData_2 } from './A'; // For our named imports
// Syntax single named import:
// import { importantData_1 }
// For our default export (foo), the name choice is arbitrary
import ourFunction from './A';
Things of interest:
Use a comma-separated list within curly braces with the matching name of the export for named export.
Use a name of your choosing without curly braces for a default export.
Aliases:
Whenever you want to rename a named import this is possible via aliases. The syntax for this is the following:
import { importantData_1 as myData } from './A';
Now we have imported importantData_1, but the identifier is myData instead of importantData_1.
In order to understand the use of curly braces in import statements, first, you have to understand the concept of destructuring introduced in ES6
Object destructuring
var bodyBuilder = {
firstname: 'Kai',
lastname: 'Greene',
nickname: 'The Predator'
};
var {firstname, lastname} = bodyBuilder;
console.log(firstname, lastname); // Kai Greene
firstname = 'Morgan';
lastname = 'Aste';
console.log(firstname, lastname); // Morgan Aste
Array destructuring
var [firstGame] = ['Gran Turismo', 'Burnout', 'GTA'];
console.log(firstGame); // Gran Turismo
Using list matching
var [,secondGame] = ['Gran Turismo', 'Burnout', 'GTA'];
console.log(secondGame); // Burnout
Using the spread operator
var [firstGame, ...rest] = ['Gran Turismo', 'Burnout', 'GTA'];
console.log(firstGame);// Gran Turismo
console.log(rest);// ['Burnout', 'GTA'];
Now that we've got that out of our way, in ES6 you can export multiple modules. You can then make use of object destructuring like below.
Let's assume you have a module called module.js
export const printFirstname(firstname) => console.log(firstname);
export const printLastname(lastname) => console.log(lastname);
You would like to import the exported functions into index.js;
import {printFirstname, printLastname} from './module.js'
printFirstname('Taylor');
printLastname('Swift');
You can also use different variable names like so
import {printFirstname as pFname, printLastname as pLname} from './module.js'
pFname('Taylor');
pLanme('Swift');
Usually when you export a function you need to use the {}.
If you have
export const x
you use
import {x} from ''
If you use
export default const x
you need to use
import x from ''
Here you can change X to whatever variable you want.
The curly braces ({}) are used to import named bindings and the concept behind it is destructuring assignment
A simple demonstration of how import statement works with an example can be found in my own answer to a similar question at When do we use '{ }' in javascript imports?.
If there is any default export in the file, there isn't any need to use the curly braces in the import statement.
if there are more than one export in the file then we need to use curly braces in the import file so that which are necessary we can import.
You can find the complete difference when to use curly braces and default statement in the below YouTube video.
21. ES6 Modules. Different ways of using import/export, Default syntax in the code. ES6 | ES2015
The curly braces are used only for import when export is named. If the export is default then curly braces are not used for import.
For a default export we do not use { } when we import.
For example,
File player.js
export default vx;
File index.js
import vx from './player';
File index.js
File player.js
If we want to import everything that we export then we use *:

Importing a Promise Polyfill [duplicate]

In the react documentation I found this way to import PureRenderMixin
var PureRenderMixin = require('react/addons').addons.PureRenderMixin;
How can it be rewritten in ES6 style. The only thing I can do is:
import addons from "react/addons";
let PureRenderMixin = addons.addons.PureRenderMixin;
I hope there is a better way.
Unfortunately import statements does not work like object destructuring. Curly braces here mean that you want to import token with this name but not property of default export. Look at this pairs of import/export:
//module.js
export default 'A';
export var B = 'B';
//script.js
import A from './a.js'; //import value on default export
import {B} from './a.js'; // import value by its name
console.log(A, B); // 'A', 'B'
For your case you can import whole object and make a destructuring assignment
import addons from "react/addons";
let {addons: {PureRenderMixin}} = addons;
import PureRenderMixin from 'react-addons-pure-render-mixin';
See example here.

Categories