How to Import and Export dynamically in ES6 - javascript

In my react component directory, I setted index.js here.
import App from './App';
import Main from './Main/Main';
import Best from './Main/Best';
import Club from './Main/Club';
import Post from './Main/Post';
import Sidebar from './Sidebar/Sidebar';
export { App, Main, Best, Club, Post, Sidebar };
Usage in other js,
import {
App,
Main,
Best,
Club,
Post,
Sidebar
} from '../scripts/Containers/index';
But whenever I make component like that, should I have to write import / export statements index.js there?
Is there any magical way?
Please help me to solve out this problem!
Update (with #Bergi)
I modifed like this, and it works well.
export { default as App } from './App';
export { default as Header } from './Header/Header';
export { default as Main } from './Main/Main';
export { default as Best } from './Main/Best';
export { default as Club } from './Main/Club';
export { default as Post } from './Main/Post';
export { default as Sidebar } from './Sidebar/Sidebar';
But this didn't work
export * from './App';
export * from './Header/Header';
export * from './Main/Main';
export * from './Main/Best';
export * from './Main/Club';
export * from './Main/Post';
export * from './Sidebar/Sidebar';
In order to works with above code, I changed this in component
export default class Header extends Component {
constructor(...args) {
super(...args);
}
}
to
export class Header extends Component {
constructor(...args) {
super(...args);
}
}
I deleted export default module exports! And works second export way works(not first one)
Thanks #Bergi :)
But I think that dynamically import / export won't be able to use.
Maybe this is best way I think.

Related

Export pure functional component without decorators

I'm trying to export a component without the decorators (connect() in this case)
for unit testing with jest.
So, how could I do this:
import React, { Component } from 'react';
import { connect } from 'react-redux';
export class Header extends Component {
render(){
return <pre>Header</pre>
}
}
export default connect()(Header);
With this component (the export at the beginning doesn't work, it stills exports the connected component)
export let Header = props => {
render(){
return <pre>Header</pre>
}
}
Header = connect()(Header);
export default Header;
Use different variable for your connected component as the following code:
export let Header = props => {
render(){
return <pre>Header</pre>
}
}
let HeaderConnected = connect()(Header);
export default HeaderConnected;
Now you can import your Header freely without using connect()
This can be done without even changing default export:
export let Header = props => {
render(){
return <pre>Header</pre>
}
}
export default connect()(Header);
There may be no need to export original component for connect alone because most well-designed HOCs expose original component:
import Header from '...';
const OriginalHeader = Header.WrappedComponent;

HOC import TypeError: Object(...) is not a function

I just tried to use a simple HOC with react.
Here is the function :
import React from "react"
const withOptions = (WrappedComponent) => {
return class extends React.Component {
render() {
return <WrappedComponent { ...this.props } />
}
}
}
export default withOptions
The problem seems to be in the way i export/import it.
Imported and used in a simple way, it works :
import withOptions from "./Options"
...
class BilanClimatique extends React.Component{
...
}
const StyledBilanClimatique = withStyles(styles)(BilanClimatique)
export default withOptions(StyledBilanClimatique)
But if i use an intermediate file like index.js
import withOptions from "./Options"
export {
withOptions
}
And import it in my component like that
import {
withOptions
} from "./index"
Here is what i get
Can someone help me understand this ?
EDIT :
I found that the component that is using the HOC is imported from the same file as the HOC :
import withOptions from "./Options"
import BilanClimatique from "./BilanClimatique"
export {
withOptions,
BilanClimatique
}
And that causes the problem, but I don't understand why...
Here is a sandbox with the problem https://codesandbox.io/s/r074735yvo
This seems to be a problem with hoisting of 'exports'. From what I can see, the imports get hoisted, but I could not see anything similar for exports.
The flow which causes problem (codesandbox):
App.js:
import { BilanClimatique } from "./components/index";
./components/index.js:
// just using the "re-export" shortcut
export { default as BilanClimatique } from "./BilanClimatique";
export { default as withOptions } from "./Options";
./components/BilanClimatique.js:
import { withOptions } from "./index";
./components/Options.js:
const withOptions = WrappedComponent => {
return ... //snipped code
export default withOptions;
When App.js asks index.js for BilanClimatique, it in turn asks the same index.js for withOptions. But since exports don't seem to be hoisted, index.js has not yet made withOptions available.
How to solve:
Ordered exports:
in ./components/index.js, change the order of exports as per your dependency:
// just using the "re-export" shortcut
export { default as withOptions } from "./Options";
export { default as BilanClimatique } from "./BilanClimatique";
I would not recommend it. It is very fragile.
Use index.js to only expose to outside your namespace. Inside your namespace, rely on explicit imports.
i.e. in ./components/BilanClimatique.js:
import withOptions from "./Options";
If you have a very large codebase, use multiple index.js for exporting your "contracts". Take a look at the codebases of various library authors, I think that is the strategy they take.
I would personally recommend #2 over #3 unless you run into problems with #2.
. doesn't look as a great import path. Try to import from 'index' file.
import {
Logo,
withOptions
} from "./index"

export default usage with deconstruct

I came to a codebase that did this
//index.js
export { default } from './Tabs'
export { default as Tab } from './Tab'
//Tab.js
export default class Tab extends Component {
render() => 'Something'
}
It's understandable that the author put Tab files under a Tab folder so that in other place he can just do import './Tabs' but why within the index.js he need to deconstruct?
Lots of people follow this nomenclature where the index file is just exports which then makes the imports easier.
It lets you import from the Tabs folder without explicitly saying the index.js filename. Most importantly it lets you import things from the folder Tab in just one statement.
For Example:
// Tab/Tab.js
import React, { Component } from "react";
class Tab extends Component {
render() {
return <span>Tab</span>;
}
}
export default Tab;
// Tab/Tabs.js
import React, { Component } from "react";
class Tabs extends Component {
render() {
return <span>Tabs</span>;
}
}
export default Tabs;
// Tab/index.js
export Tab from "./Tab";
export Tabs from "./Tabs";
// Main file
import React from "react";
import { render } from "react-dom";
import { Tab, Tabs } from "./Tab";
const App = () => (
<div>
<Tab />
<Tabs />
</div>
);
render(<App />, document.getElementById("root"));
demo: https://codesandbox.io/s/rr6klxj5j4
You can have a single default export from your file, Also writing
//index.js
export Tabs from './Tabs'
export Tab from './Tab'
will export them as a named export which you can later import as
import { Tabs, Tab } from './Tabs'
Also to understand the point default import is nothing different from an export named as default, so when you write
//index.js
export { default } from './Tabs' // Exports the Tabs as default
export { default as Tab } from './Tab' // imports the default from Tab and exports it as Tab
You could also write the above as
export { default } from './Tabs'
export Tab from './Tab'
In the above two cases you would import them as
import Tabs, { Tab } from './Tabs'
Check Error Exporting a component without importing for some more details

How to define props for react-navigation with Flow

I am working on a simple React Native App, and have decided to user react-navigation. I have also decided to go with Flow for static type checking. What I can't figure out, is how to define navigation related props with Flow.
e.g. I define my App.js to use StackNavigator like so:
import StackNavigator from 'react-navigation';
import Main from './app/containers/Main';
const App = StackNavigator({
Main: { screen: Main },
});
export default App;
then I define my Main class, but I don't know how to reference react-navigation in my props:
// #flow
import React, { Component } from 'react';
import { View, Text } from 'react-native';
type Props = {
navigate: ????
};
type State = {};
class Main extends Component<Props, State> {
...
}
According to https://github.com/react-navigation/react-navigation/issues/3643
import { NavigationState, NavigationScreenProp } from 'react-navigation';
type Props = {
navigation: NavigationScreenProp<NavigationState>
};
Import NavigationScreenProp from react-navigation:
// #flow
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import { NavigationScreenProp } from 'react-navigation';
type Props = {
navigate: NavigationScreenProp<{}>
};
type State = {};
class Main extends Component<Props, State> {
...
}
react-navigation has a flow file. Maybe you can import from there or just copy-paste
https://github.com/react-navigation/react-navigation/blob/master/flow/react-navigation.js#L72
To prevent Cannot import the type NavigationState as a value. Use the import type instead.
// #flow
import React, { Component } from 'react';
import type { NavigationState, NavigationScreenProp } from 'react-navigation';
type Props = {
navigation: NavigationScreenProp<NavigationState>
}
type State = {}
class Main extends Component<Props, State> {
...
}
You can also add below to .flowconfig to prevent flow-typed/npm/redux-devtools-extension_v2.x.x.js:23:33
[lints]
deprecated-utility=off

Prefer default export eslint error

I am getting this eslint error:
Prefer default export
import React, { Component } from 'react';
class HomePage extends Component {
render() {
return (
<div className="Section">HomePage</div>
);
}
}
export { HomePage };
I have tried doing:
export { default as Homepage };
and then I get a fatal parsing error.
Then I changed it to:
export default HomePage;
Which clears the eslint error.
But then throws:
'./HomePage' does not contain an export named 'HomePage'.
Because I am calling HomePage like this:
import { HomePage } from './HomePage';
If I remove the brackets then I get this error:
"export 'default' (imported as 'HomePage') was not found in
'./HomePage'
import HomePage from './HomePage';
<PrivateRoute exact path="/" component={HomePage} />
What would be the proper way of changing this to the preferred default export?
From eslint-plugin-import
When there is only a single export from a module, prefer using default export over named export.
class HomePage extends Component {
//....
}
export default HomePage
In another file :
import HomePage from './Hello';
Check here codesandbox
Here's an example using functions:
function HomePage() {
function aHelperMethod() {
//
}
return {
aHelperMethod,
}
}
Now to import it in another file
import HomePage from './Hello';
And to use it you'll have to instantiate it
const homePage = HomePage()
homePage.aHelperFunction()
In some cases there should be more than one named export in the module.
export const foo = 'foo';
export const bar = 'bar';

Categories