Organizing React Components - javascript

I am building a React App which consists of lot of smaller components. At present I am importing the components in app.js like this:
import Nav from './components/nav'
import ColorPicker from './components/colorPicker'
class App extends Component {
render() {
return (
<div>
<Nav />
<ColorPicker />
</div>
);
}
}
export default App;
Each component is a separate js file (nav.js, colorPicker.js). Is there anyway to just import everything in components folder so I don't have to explicitly specify importing of the components.

I'm not sure if there is a way to just import everything from a folder with one module per file, but you can make a kind of index.js file in which you would import everything that you will want, then:
export * from nav;
export * from colorPicker;
And then you only have to import your one index file from which you can: import {nav, colorPicker} from './components/things';

You always have to explicitly set the import of the components you use, but what you can do is decrease the amount of code typed by setting up an index file where you export all components you want to make available in said file, like this for example:
./components/index.js
import Component1 from './Component1';
import Component2 from './Component2';
import Component3 from './Component3';
export {
Component1,
Component2,
Component3,
};
Then import the needed components in the desired file like this:
./app.js
import { Component1, Component2 } from './components';
class App extends Component {
render() {
return (
<div>
<Nav />
<ColorPicker />
</div>
);
}
}
export default App;
Tree structure
app.js
components
+---
Component1.js
Component2.js
index.js

If you can add a babel plugin, you can use babel-plugin-wildcard, that is a plugin that makes exactly what you want.
Taken from NPM:
With the following folder structure:
|- index.js
|- dir
|- a.js
|- b.js
|- c.js
the following JS:
import * as Items from './dir';
will be compiled to:
const Items = {};
import _wcImport from "./dir/a";
Items.A = _wcImport;
import _wcImport1 from "./dir/b";
Items.B = _wcImport1;
import _wcImport2 from "./dir/c";
Items.C = _wcImport2;
meaning you will be able to access the items using Items.A and Items.B.
You can also selectively choose files using:
import { A, C } from "dir/*";
which in the above example would convert to:
import A from "./dir/a";
import C from "./dir/c";
The above is like doing:
import * as temp from "dir";
const { A, C } = temp;
Answer found inside this post.

Related

How to set up a directory as a "module" for bulk JavaScript import?

Just like we'd do
import * as React from 'react';
and then for example
const [state, setState] = React.useState(false);
I would like to import a bunch of my exported stuff from a folder to then access using dot-notation of the imported module.
For example, an "AppBar" component using "AppsButton", "HomeButton", "BugReportButton" and "HelpButton", which I put as jsx files in the same folder. These files each "export default" functions for their views. I would like to do:
import AppBar from '#mui/material/AppBar';
import * as AppBarContent from ".//AppBar"; // hopefully the correct syntax for the folder named "AppBar", which this file sits in
and then use each component in the view like:
<AppBar>
<AppBarContent.AppsButton />
<AppBarContent.HomeButton />
<AppBarContent.BugReportButton />
<AppBarContent.HelpButton />
</AppBar>
I looked about and found this resource, but wasn't certain it's the same thing I'm after and when I made the suggested index.js with the following content it didn't change anything (I could've done it wrong).
index.js:
exports.AppsButton = require("./AppsButton");
exports.HomeButton = require("./HomeButton");
exports.BugReportButton = require("./BugReportButton");
exports.HelpButton = require("./HelpButton");
exports.HelpDrawer = require("./HelpDrawer");
Any single resource or some steps how to achieve this please?
You cannot have more than one default export in one file. Use named exports as follows:
appbar.js:
export const BugReport = () => <div> bug </div>
export const Header = () => <div> header </div>
export const Footer = () => <div> Footer </div>
Then you can import and use them as follows:
header.js
import React from "react";
import * as Appbar from "./appbar";
function Header(props) {
return (
<div>
<Appbar.BugReport/>
<Appbar.Footer/>
<Appbar.Header/>
</div>
);
}
export default Header;
I actually found the solution to this when checking out some coding standards for React:
One point says "Create a index.js within each folder for exporting".
Source: https://www.jondjones.com/frontend/react/react-tutorials/react-coding-standards-and-practices-to-level-up-your-code/
After I've added an index.js to each folder that imports all components in that folder and then exports them all, I can import individual components from that folder level as a "module" (apologies if terminology incorrect) and also import all as a named source that I can access using dot notation.
Note that for this to work the imports (of indexed exports) must now include curly braces.
For example all the buttons going into a new folder "buttons" and having an index.js:
import AppsButton from "./AppsButton";
import HomeButton from "./HomeButton";
import AppHomeButton from "./AppHomeButton";
import HelpButton from "./HelpButton";
export {AppsButton, HomeButton, AppHomeButton, HelpButton}
Then the AppBar.js a folder up can do either:
import {AppsButton, HomeButton, AppHomeButton, HelpButton} from "./buttons"
with
<AppBar>
<AppsButton />
<HomeButton />
<BugReportButton />
<HelpButton />
</AppBar>
or:
import * as buttons from "./buttons"
with:
<AppBar>
<buttons.AppsButton />
<buttons.HomeButton />
<buttons.BugReportButton />
<buttons.HelpButton />
</AppBar>
(I went for the former in this case, but I can see now how in other areas of my code-base I could have things like appBarContent.buttons.AppsButton reused elsewhere using this approach...)

Good practice to import images in ReactJS?

I am adding multiple images in my web page by placing each image in same directory that of components (see screenshot) How can I place the image files in another folder and then access them inside my components.
content.js:
import React, { Component } from 'react';
import java from './java.png';
import neural from './neural.png';
import future from './future.gif';
import neuralnet from './neuralnet.jpg';
import dsa from './dsa.png';
import dl from './dl.jpg';
import ml from './ml.jpg';
import python from './python.png';
import ai from './ai.jpg';
<img className="futuregif" src={future} alt="gif" height="240" width="320"></img>
<img className="javacardimg" src={java} alt="Java" height="65" width="65"></img>
<img className="neuralcardimg" src={neural} alt="neural" height="65" width="65"></img>
and so on.. for all other images
Components and image files are getting mixed together is there any other specific way to do it by making a image folder but then what should be the path in src="".
File structure:
To clarify my comment.
Create a directory assets containing all your assets like images.
Then import the right path and load your content like:
import neural from './assets/images/neural.png';
class myComponent extends Component {
render() {
return (<div><img src={neural} alt=""/></div>);
}
}
In my point of view you can create a js file and export const imageName. in const you can specify your image path.
constant.js
import React from 'react';
import java from './java.png';
export const javaImg = java;
Then in your component file you need to import that js file and you can use those const according to your requirement.
Component
import constant from './constant';
class x extends Component {
constructor(props) {
super(props);
console.log(constant.javaImg);
}
}
export default x;
If you are importing images in same component it'll work but the component will become a lengthy and complex looking.
so my suggestion is like this.

import and export of modules in ES6

I am in the process of refactoring my structure of import and export of modules. The goal here is to import UserActions through index.js, in multiple files (namely, in UserReducer.js and Home.js).
the project's tree structure looks like:
js
|_ modules
| |_ user
| | |_index.js
| | |_UserActions.js
| | |_UserReducer.js
| | |_UserSagas.js
|_ containers
| |_ Home.js
This is the content of modules/user/index.js:
import * as UserActions from './UserActions'
import * as UserSagas from './UserSagas'
import UserReducer from './UserReducer'
export { UserActions, UserReducer, UserSagas }
Initially the actions were being imported directly from the UserActions file, in both UserReducer.js and Home.js as follows:
in UserReducer.js: import * as UserActions from './UserActions'
in Home.js: import * as UserActions from 'modules/user/UserActions'
And everything was working correctly. Now I want these two imports to use the index.js file above.
step 1)
inside UserReducer, i change the import line from:
import * as UserActions from './UserActions'
to:
import { UserActions } from '.' // fetches the named export from index.js
This is working.
step 2)
inside Home.js, i change the import line from:
import * as UserActions from 'modules/user/UserActions'
to:
import { UserAction } from 'modules/user'
Now webpack doesn't complain but the browser throws error in UserReducer, that UserActions is undefined.
Finally:
using the import { UserActions } from 'path_to_index.js' notation works, as long as I use it in one place only (could be in either file).
As soon as I use it in both places, all hell breaks loose...
Any ideas? Thanks
Edit: I realize that the errors above occur only if the user/index.js imports and exports UserSagas as well. If I import the UserSagas directly from their file instead of adding it to index.js, the app runs correctly.
Turns out #estus is correct in that even importing another exported part from index.js would cause circular dependency.
I wanted index.js to be the unique interface to users, but it looks like that will only apply to components outside of "users". Internally, the import will be directly from the actions file

Index.js module imports with webpack

My code is organised as follows:
where,
Resources/ActionLog/Components/Layout.js
import React from 'react';
export default class Layout extends React.Component {
render() {
return (
<p>Test</p>
);
}
}
Resources/ActionLog/Components/index.js
export * from './Layout';
Resources/ActionLog/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import Layout from './Components'; // <--- ISSUE HERE.
const app = document.getElementById('app');
ReactDOM.render(
<Layout/>,
app
);
Why does Layout not get imported using this setup??
If i change the line to read,
import Layout from './Components/Layout';
it works fine, but otherwise Layout is always undefined! Even when if i try,
import Layout from './Components/index';
I am using webpack as my module bundler, and have achieved something similar before, I just don't see why/how this is different..
Why does Layout not get imported using this setup??
Layout.js has a default export. However, export * from './Layout.js will only export the named exports (of which there are none). In other words, Components/Layout.js doesn't have any exports at all, so nothing can be imported.
But even if it did have named exports, import Layout from './Components/index'; imports the default export, but Components/index.js doesn't have a default export.
There are a couple of ways this could be solved. The one that makes the most sense is probably to export the default export of Layout.js as named export in Components/index.js. You will presumably have multiple files each exporting a component. I assume Components/index.js should export a map of all these components in which case you have to use named exports.
The changes you have to make:
// in Components/index.js
export {default as Layout} from './Layout';
// in ActionLog/index.js
import {Layout} from './Components'; // use a named import

Re-export default in ES 6 modules

In ES6, is it possible to shorten the following code. I have an App.js file and an index.js.
index.js
import App from './App';
export default App;
Something like this
index.js
export default App from './App.js'
If you use proposal-export-default-from Babel plugin (which is a part of stage-1 preset), you'll be able to re-export default using the following code:
export default from "./App.js"
For more information see the ECMAScript proposal.
Another way (without this plugin) is:
export { default as App } from "./App.js"
The above is a very common practice when separate files, each with its own export, have all something in common, for example, utils, so if, for example, one would want to import 3 utility functions, instead of having to write multiple imports:
import util_a from 'utils/util_a'
import util_b from 'utils/util_b'
import util_c from 'utils/util_c'
One could import any of the utilities in a single-line:
import { util_a, util_b , util_c } from 'utils'
By creating an index.js file in the /utils folder and import all the defaults of all the utilities there and re-export, so the index file will serve as the "gateway" for all imports related to that folder.
This is a bit of repetition from the previous answers, but to clarify the difference in two options:
1. Default export
(This appears to be what OP wants)
// index.ts
export { default } from './App'
Then, in a different file:
import App from './index'
2. Named export
export { default as App } from './App'
Then, in another file:
import { App } from './index'
Bonus: named → default export
If ./App uses a named export, but you want to re-export it as a default export, you can do that too:
export { App as default } from './App'
Then, in another file:
import App from './index'
These will work with react as vsync's answer states.
Bonus #2: export everything
Say you have a file that exports multiple items:
// App.ts
export const first = 1
export const second = 2
const final = 3
export default final
You can then re-export them directly:
// index.ts
export * from './App'
You can now import these easily:
import final, { first, second } from './index'
Bonus #3: * import
You can import all variables exported by another file as a single variable.
// index.ts
import * as App from './App'
App.first === 1 // true
import App from './App';
export default App;
⬇
Babel 7 (with #babel/preset-react) can transform the below:
export { default as App } from './App.js';
Related discussions:
TC39 proposal:
https://github.com/tc39/proposal-export-default-from#common-concerns
The only working solution is :
import App from './App';
export default App;
If you export your module like this
export { default as App } from './App.js';
Then it's not a default export anymore and you'll get an error if you try to import it as a default import.
import App from './App';
export default (App);
This work for me in default 'create-react-app' application

Categories

Resources