How did this come about?
Recently I have been using Material UI, and I really like the way I could pull in components through destructuring assignment in Javascript:
import { Card, CardContent, Container, Grid, Typography } from "@material-ui/core"
The way I would do this in the past
Typically, in the past, I would probably export my component like this from the actual component file:
// src/components/Artist/ArtistListItem.js
import React from "react"
const ArtistListItem = () => {
return (
// JSX
)
}
export default ArtistListItem
This would allow me to import that component like this within one of my Next.js pages:
// src/pages/spotify.js
import ArtistListItem from "../components/Artist/ArtistListItem
This really isn't too bad when getting an app up and running, but if I am importing in even just a half dozen components, the import section of my file quickly gets a little overwhelming:
// src/pages/spotify.js
import ArtistList from "../components/Artist/ArtistList"
import ArtistListItem from "../components/Artist/ArtistListItem"
import ArtistAvatar from "../components/Artist/ArtistAvatar"
import PageHeading from "../components/Page/PageHeading"
import PageSubheading from "../components/Page/PageSubheading"
import PageSidebar from "../components/Page/PageSidebar"
import PageFooter from "../components/Page/PageFooter"
If the import sections of your pages start to look like this, you could maybe benefit from a refactor of your imports using destructuring assignment.
Cleaning it up with destructuring
My desired outcome
Looking at the above example, let's take a look at the the end-result I would actually like to achieve:
// src/pages/spotify.js
import { ArtistList, ArtistListItem, ArtistAvatar } from "../components/Artist"
Leveraging exports within our index files
The magic here really lies within index.js
files that I will place throughout our file structure. Using the above example, I can place an index.js
file within my Artist
directory that will export out the artist-related components, making them available to destructuring assignment.
My folder structure might then look like this:
├── src
│ └── components
│ └── Artist
│ ├── ArtistList.js
│ ├── ArtistListItem.js
│ ├── ArtistAvatar.js
│ └── index.js
Now, just to take a quick look at that component file from earlier:
// src/components/Artist/ArtistListItem.js
import React from "react"
const ArtistListItem = () => {
return (
// JSX
)
}
// Note the default getting exported out here
export default ArtistListItem
Now within my newly-added index.js
I can give access to the ArtistListItem
component during restructuring like this:
// src/components/Artist/index.js
// Import the default from each component value, and rename here if needed
import { default as ArtistList } from "./ArtistList"
import { default as ArtistListItem } from "./ArtistListItem"
import { default as ArtistAvatar } from "./ArtistAvatar"
// I export out the components from this file
export default {
ArtistList,
ArtistListItem,
ArtistAvatar
}
Finally, I should be able to pull them in as desired within my page component:
// src/pages/spotify.js
import { ArtistList, ArtistListItem, ArtistAvatar } from "../components/Artist"
Taking it further
Destructuring any component from my components directory
While what I have now is much better, as it stands now, if I were to pull in Page
components, there would be redundancy again within our imports:
// src/pages/spotify.js
import { ArtistList, ArtistListItem, ArtistAvatar } from "../components/Artist"
import { PageHeading, PageSubheading, PageSidebar, PageFooter } from "../components/Page"
It would be ideal I think to be able to simply pull in any component from the components
directory. Again, just as before, the magic here would be adding another index.js
file to the components
directory:
├── src
│ └── components
│ ├── Artist
│ │ ├── ArtistList.js
│ │ ├── ArtistListItem.js
│ │ ├── ArtistAvatar.js
│ │ └── index.js
│ └── Page
│ │ ├── PageHeading.js
│ │ ├── PageSubheading.js
│ │ ├── PageSidebar.js
│ │ ├── PageFooter.js
│ │ └── index.js
│ └── index.js // Add this here
Within that main index.js
in our components
directory, similarly to how I made the individual components available to be destructured within their respective index.js
files, I am going to do the same thing within src/components/index.js
:
// src/components/index.js
import { ArtistList, ArtistListItem, ArtistAvatar } from "./Artist"
import { PageHeading, PageSubheading, PageSidebar, PageFooter } from "./Page"
export default {
ArtistList,
ArtistListItem,
ArtistAvatar
PageHeading,
PageSubheading,
PageSidebar,
PageFooter
}
Finally, we should be able to pull in any component by simply destructuring an import of the components
directory:
// src/pages/spotify.js
import {
ArtistList,
ArtistListItem,
ArtistAvatar
PageHeading,
PageSubheading,
PageSidebar,
PageFooter
} from "../components"