DEV Community

loading...
Cover image for Exports and Imports and Defaults, Oh My!

Exports and Imports and Defaults, Oh My!

Laurie
Software dev at Netflix | DC techie | Conference speaker | egghead Instructor | TC39 Educators Committee | Girls Who Code Facilitator | Board game geek | @laurieontech on twitter
Updated on ・3 min read

I've been starting projects using cli or starter templates lately and one of the things I've noticed is how many pieces of code are included that we kind of take for granted.

One of the first snippets that caught my attention was the line of code that exports the App component when you generate a new React project.

class App extends Component {
  render() {
    return (
      <h1>This is my application.</h1>
    )
  }
}

export default App
Enter fullscreen mode Exit fullscreen mode

So I'd like to take this opportunity to walk through this short but powerful piece of code and break down what is happening and why it's there.

ES6 Modules

ECMAScript, the standard Javascript is based on, introduced the concept of modules in ES6.

A module is a self-contained unit of code. That code can expose assets to other modules using export. It can also consume assets from other modules using import.

The code above is an example of how React uses this concept to pass things around from component to component.

This is important to keep in mind because the ES6 spec is slightly different.

One Step at a Time

Let's examine just this line of code.

export default App
Enter fullscreen mode Exit fullscreen mode
  • First we have export, that keyword is exposing content to other modules.

  • Next, we have default.

Default is one of the types of exports available in ES6. Using the default keyword we're saying that if you import this module and don't specify what you are importing from it, you'll get this! For any given module we can only have one default export.

  • Finally, we have the name of the asset we're exporting, in this case that's App.

Ok, Now Let's Use It

Since App is exported, we can use it in another module if we import it.

import App from "./App"
Enter fullscreen mode Exit fullscreen mode

This exact line of code appears in index.js when you create a React project.

We import default exports using the syntax above. What's interesting is that App is just a name assignment here. This statement is really saying, you haven't specified an asset from .App so I'm going to take the one exported by default and assign it a name for reference purposes.

As a result, it turns out that we don't have to name it App at all. It's ONLY a name assignment.

import Whatever from "./App"
Enter fullscreen mode Exit fullscreen mode

In this case, Whatever is still our App component! And we can use it.

ReactDOM.render(<Whatever />, document.getElementById('root'));
Enter fullscreen mode Exit fullscreen mode

Missing Default, aka Named Imports

What about exporting multiple assets or non-default assets? What does that look like?

export class App extends Component {
  render() {
    return (
      <h1>This is my application.</h1>
    )
  }
}
Enter fullscreen mode Exit fullscreen mode

The above is an example of the same App asset exported, but without using the default keyword.

This will work, but we can't import it the same way. If I try to do this

import App from "./App"
Enter fullscreen mode Exit fullscreen mode

It gives me this error

Attempted import error: './App' does not contain a default export

My import statement doesn't know what it's assigning to that App name!

Without a default export, I need to explicitly name what I'm looking to import. That's why it's called a named import in ES6.

import {App} from "./App"
Enter fullscreen mode Exit fullscreen mode

This looks whole lot like destructuring assignment! While it's technically different, buildtime vs. runtime, it's a helpful way to remember the syntax. So this statement is really saying, look inside the whole .App module. I want the exported asset called App inside that module.

Give Me Everything!

Since it's possible to export multiple assets in a single module it's also necessary to be able to import more than one at a time. We can do this as long as we know the names.

import {App, Dev, Post} from "./App"
Enter fullscreen mode Exit fullscreen mode

And you can have both default and named exports in a single module and import them together. Let's pretend App is still the default export.

import App, {Dev, Post} from "./App"
Enter fullscreen mode Exit fullscreen mode

Voila!

Not Too Bad

It's not super complicated once you break it down. However, too often we see throwaway lines of code inside frameworks and projects that we don't take the time to understand. I encourage you to curiously explore everything you see! It'll make you a better programmer.

Discussion (17)

Collapse
terabytetiger profile image
Tyler V. (he/him)

Not that there's a use for this, but is there a way to assign names to the imports when running

import {App, Dev, Post} from "./App"

For example, is there a way to import App as Whatever and Post as Thing?

Collapse
laurieontech profile image
Laurie Author • Edited

Yup!

If it's a named import it's this.

import {App as Whatever} from "./App"
Collapse
gmartigny profile image
Guillaume Martigny

Nice article. You just haven't talked about the * globber for import. You can use it to import everything from a module under a "namespace".

import * as Namespace from "module";
const app = new Namespace.App();
Enter fullscreen mode Exit fullscreen mode
Collapse
laurieontech profile image
Laurie Author

Definitely an important thing to know. I tried to keep it bite sized, so I didn't cover every part of imports and exports (like aliases). But great to have in the comments as additional information :)

Collapse
salunmarvin profile image
Salun Marvin

Excellent approach. It's so easy how we get lost about using frameworks and not understand what it does.

Collapse
qcgm1978 profile image
Youth

Another interesting style is introducing alias:

//You can import the default export by either

import Test1 from './test';
//or

import {default as Test2} from './test';
Enter fullscreen mode Exit fullscreen mode
Collapse
laurieontech profile image
Laurie Author

Definitely. Another nice piece of syntax to understand.

Collapse
thefoxboxman profile image
John De Costa

Thank you Laurie. That is by far the best explanation I have read on this subject. Well done you! Keep up the excellent work.

Collapse
laurieontech profile image
Laurie Author

Thank you so much!

Collapse
darkain profile image
Vincent Milum Jr

As someone who doesn't use React, I'm curious as to why so much biolerplate code is even needed for a basic simple one line of text? I work in the Altaform framework, and it would literally just be the line of text with zero boilerplate, and it would just work.

Collapse
laurieontech profile image
Laurie Author

So this is defining a component that can then be used on multiple pages. Components can have the render function as well as other functions, styles, etc. I’ll be doing another post on that.
But frameworks come with different strengths and different “powers”. They all have use cases where they make more sense.

Collapse
worc profile image
worc

because the point of the library isn't "a basic simple one line of text." the point is create much larger and much more complex applications. once you're in the react ecosystem you have a much larger toolset to pull from than if you were just generating html strings with your own homegrown solution.

Collapse
tamouse profile image
Tamara Temple

Great post, really clear explanation and examples. I think it's very helpful to take a small piece like this, that we see everyday, and break it down. Well done!

Collapse
awkale profile image
Alex W Kale

This explanation is so helpful and clear. I finally feel I fully understand imports and exports.

Collapse
laurieontech profile image
Laurie Author

So glad it resonated with you!

Collapse
darryl profile image
Darryl Young

Nice article, Laurie. Thanks for sharing.

Collapse
meddy672 profile image
Matt Eddy

Very well put together article.