110

I just started a new React project and decided to use this pattern, which basically groups files according to their respective component:

├── actions
│   ├── LaneActions.js
│   └── NoteActions.js
├── components
│   ├── App
│   │   ├── App.jsx
│   │   ├── app.css
│   │   ├── app_test.jsx
│   │   └── index.js
│   ├── Editable
│   │   ├── Editable.jsx
│   │   ├── editable.css
│   │   ├── editable_test.jsx
│   │   └── index.js
...
│   └── index.js
├── constants
│   └── itemTypes.js
├── index.jsx
├── libs
│   ├── alt.js
│   ├── persist.js
│   └── storage.js
├── main.css
└── stores
    ├── LaneStore.js
    └── NoteStore.js

What's confusing me is how index.js works in this case. As quoted:

The index.js files are there to provide easy entry points for components. Even though they add noise, they simplify imports.

What the article doesn't do is go in depth of what's inside these files. In the case of the Editable component, what would Editable.jsx and index.js ideally look like?

Carl Edwards
  • 13,826
  • 11
  • 57
  • 119
  • 13
    An `index.js` file allow you to `import` (or `require()`) its parent folder as a module. This behavior is copied from Node.js, which has covers this in its documentation under [Folders as Modules](https://nodejs.org/dist/latest-v7.x/docs/api/modules.html#modules_folders_as_modules) – "*If there is no package.json file present in the directory, then Node.js will attempt to load an `index.js` or `index.node` file out of that directory.*" – Jonathan Lonowski May 21 '17 at 02:07

5 Answers5

141

This exact structure suggests that, for example, the Editable component would have everything about that component inside Editable.jsx. and I mean that your component code stays inside that file.

Now what's index for ? Inside index you would simply do something like this:

import Editable from './Editable.jsx';

export default Editable;

and that's it. This is helpful because inside other components or containers you can do this:

import Editable from '../Editable';

because it tries to access the index.js file by default thus not requiring any more info from you. It would import automatically the index.js file which imports the actual component itself. If you did not have an index.js file you would have had to do this:

import Editable from '../Editable/Editable';

which is kind of awkward. I don't like to have an index file that all it does is import a component and export it. What I usually do is just have all my component code inside the index.js file without the need of the Editable.jsx at all. That's up to you so feel free to take the approach you like better.

G4bri3l
  • 4,996
  • 4
  • 31
  • 53
  • 1
    Thank you very much for clearing this up for me. Just out of curiosity, do you usually keep keep your files (css, test, etc) in the component directories pascal cased or snake case (as seen in the article)? I ask because in your case the index file takes place of the pascal cased component file. – Carl Edwards May 21 '17 at 02:55
  • At the end of the day it's a personal choice but I prefer to use pascal case because it is a common style choice when it comes to js. – G4bri3l May 21 '17 at 02:59
  • I guess a benefit of the index.js inside a directory will force you to only have one component per directory. I committed the sin of creating a folder called component, and inside placing many components.js files, I came across pattern describe on this thread, and I like it. Also thanks for the clear explanation. – Jozcar Oct 04 '17 at 02:22
  • 18
    You can also shorten the index to a single line like: `export { default } from './Editable';` – Razzlero Aug 27 '19 at 04:39
  • When I do that Ctrl + Click no more works, I have to give a relative path for that. Does anyone have a guess how I can make it work without using a relative path so I can use index.js for components? – Zeeshan Ahmad Khalil Aug 19 '22 at 10:15
  • @Razzlero or even `export * from './Editable'` – Francisco Gomes Feb 01 '23 at 23:49
42

If one is using this directory per component pattern looking for a clean way to organize and access your modules, then the example above with a default export won't work with multiple files, e.g; this structure with a reducer directory:

── reducers
│   ├── todoReducer.js
│   └── filterReducer.js
│   └── themeReducer.js
│   └── index.js
├── components
    ├── App.js
    ├── app.css
    └── index.js

So reducers/index.js would look something like this:

// index.js
import filterReducer from './filterReducer';
import todoReducer from './todoReducer';
import theme from './themeReducer';

export { filterReducer, todoReducer, theme };

...whether originally exported as default or named files in their original files, they are named exports now, and can be used cleanly in App.js as follows:

// App.js
import { filterReducer, todoReducer, theme } from '../reducers';

So we can avoid all this noise:

import filterReducer from './reducers/filterReducer';
import todoReducer from './reducers/todoReducer';
import theme from './reducers/theme';
chrisz
  • 1,371
  • 13
  • 8
  • 1
    Is there a smart way to handle nested index files? E.g. `common/index.js` that "collects" and exports from `common/components/index.js`. Do I have to import and the export all components separately? – Kikkomann Jan 04 '22 at 20:35
19

You can also leverage it for module namespaces, e.g.

//MyNamespace/index.js

import Mod1 from './Mod1' //assumes ./Mod1.js
import Mod2 from './Mod2' //assumes ./Mod2.js

export{
  Mod1,
  Mod2
}

Then in other files you can import with a namespace:

//SomeOtherFile.js

import * as NamespaceToUse from './MyNamespace'

// Then access as:
NamespaceToUse.Mod1
NamespaceToUse.Mod2
Bryan Liff
  • 439
  • 3
  • 7
1

There is no real benefit to using indexes for a front-end web application (whether written in React or not). If anything they are detrimental to optimal work on such project.

Organising imports should be automated and developer should not be concerned with it at all. Importing needed modules (component or not) can be automated by IDE suggestion (Intellij, WebStorm, VSC, all have those features), all you need to do is to start typing a Component's name.

Organising and optimising import structure can be done automatically on save via tools like prettier-plugin-organize-imports. There really is no need to manually interfere with imports, unless you have an import conflict.

Given that applications tend to grow, and future component folder structure is not deterministic, upkeeping of index files(dead weight) is an unnecessary overhead. Also most IDE's will open the index file instead intended Component if you ctrl/CMD click on a Component name, which is rather annoying and just distracts from you getting where you need to be (and if you need to write a lot of code, and need to look into dozens of components every minute, will become a real pain real fast).

Where indexes may be useful is, when you're writing a modular library (not an app), and you'd like to organise imports for the actual users of your library. You then also have the need of separating internal code from public/documented code. Libraries tend to have a more rigid structure, with clearer top level modules, which follow a specific segregation, which makes indexes less likely to be edited unless a new public/documented functionality needs to be exposed or deprecated. In this case indexes are useful, since they effectively create the interface for your library.

Based on the above indexes do not have a useful purpose in web applications source, but unfortunately they seem to be fashionable in some projects.

1

We currently have a component index file like this

/components/index.js
export { AutoCompleteInput } from './AutoCompleteInput';
export { AutoScrollWidgetRepositioning } from './AutoScrollWidgetRepositioning';
export { BrowserMessages } from './BrowserMessages';
export { CheckboxInput } from './CheckboxInput';

And a component index file like this

/components/AutcompleteInput/index.js
/* eslint-disable import/prefer-default-export */
export { default as AutoCompleteInput } from './AutoCompleteInput';

This means we can import components like this into other components.

/componnts/Form/Form.jsx
import {
  AutoScrollWidgetRepositioning,
  BrowserMessages,
  HeadSection,
  InitialWidgetLoadEventManager,
  PageLayout,
} from '..';

This makes the import tree clean and tidy, however the downside of this, which i am currently finding out is that there are dependency cycle errors i.e. the import is importing itself, thus an issue. I am coming to the conclusion that index files may better be the actual component so the imports are not import { CheckboxInput } from './CheckboxInput/CheckboxInput' and stay as import { CheckboxInput } from './CheckboxInput'.

TLDR: index files prevent an echo, but don't over use them else you may come across a cyclical import issue.

Jeremy
  • 1,170
  • 9
  • 26