Skip to content

Importing and Exporting Components

Overview

The magic of components lies in their reusability: you can create components that are composed of other components. But as you nest more and more components, it often makes sense to start splitting them into different files. This lets you keep your files easy to scan and reuse components in more places.

You will learn

  • What a root component module is
  • How to import a component from another file
  • How ReactPy expresses "private" and "public" components
  • How to import and export multiple components from one file
  • How to split components into multiple files

The root component module

In Your First Component, you made a profile component and a gallery component that renders it:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from reactpy import component, html


@component
def profile():
    return html.img(
        {"src": "https://i.imgur.com/MK3eW3As.jpg", "alt": "Katherine Johnson"}
    )


@component
def gallery():
    return html.section(
        html.h1("Amazing scientists"),
        profile(),
        profile(),
        profile(),
    )
1
2
3
4
img {
    margin: 0 10px 10px 0;
    height: 90px;
}

These currently live in a single module. Whichever module holds the component you hand to an executor is your root component module — the ASGI executor in Creating a Standalone React App takes that component directly:

from reactpy.executors.asgi import ReactPy

from app import gallery

my_app = ReactPy(gallery)

Which module plays this role depends on your executor. The middleware executor takes dotted paths instead, e.g. ["my_components.hello_world"], and the CSR executor takes a path to a file whose root component it mounts.

Exporting and importing a component

What if you want to change the landing screen in the future and put a list of science books there? Or place all the profiles somewhere else? It makes sense to move gallery and profile into their own module. This makes them more modular and reusable in other files. You can move a component in three steps:

  1. Make a new Python file to put the components in.
  2. Define your component functions in that file. Unlike JavaScript, Python has no export keyword — every name defined at module level is importable.
  3. Import it in the module where you'll use the component.

Here both profile and gallery have moved into a new file called gallery.py. Now app.py imports gallery from it:

1
2
3
4
5
6
7
8
from gallery import gallery

from reactpy import component


@component
def app():
    return gallery()
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
from reactpy import component, html

__all__ = ["gallery"]


@component
def _profile():
    """Used only inside this module, so it stays out of ``__all__``."""
    return html.img({"src": "https://i.imgur.com/QIrZWGIs.jpg", "alt": "Alan L. Hart"})


@component
def gallery():
    return html.section(
        html.h1("Amazing scientists"),
        _profile(),
        _profile(),
        _profile(),
    )

Notice how this example is broken down into two component files now:

  1. gallery.py:
    • Defines the _profile component, which is only used within the same file and is kept private.
    • Makes gallery the public component of the module.
  2. app.py:
    • Imports gallery from gallery.py.
    • Defines the root app component.

Note

ReactPy does not care which module a component is defined in, so unlike ReactJS there is no distinction between "default" and "named" exports. from gallery import gallery, profile and two separate import statements mean the same thing.

Public and private components

ReactJS lets you keep a component unexported so that only its own file can use it. Python has no equivalent enforcement, but it has two widely respected conventions that express the same intent.

A leading underscore marks a name as private to its module:

@component
def _profile():
    ...

And __all__ lists the names a module publishes. It is what a star import exports, and what linters and type checkers read to decide what is public API:

__all__ = ["gallery"]

This is why _profile is both underscore-prefixed and absent from __all__ in the example above.

Pitfall

These conventions are advisory, not enforced. from gallery import _profile still works, because Python has no private keyword. Do not reach for underscore-prefixed names from another module, and do not rely on them being unavailable — treat a broken convention as a bug in the importing code, not as protection.

Deep Dive

Naming modules and components

Because imports name modules rather than files, give both meaningful names. scientists.py defining gallery and _profile reads better than utils.py defining Gallery, and it also keeps you consistent with the rest of the docs, which write components in snake_case.

Components should still be called everywhere they are used, so a component used by two modules must be imported in both of them. There is no global component registry to fall back on.

Exporting and importing multiple components from the same file

What if you want to show just one profile instead of a gallery? Then app.py needs profile too. Add it to the module's __all__ and import it by name:

1
2
3
4
5
6
7
8
from gallery import gallery, profile

from reactpy import component, html


@component
def app():
    return html.div(profile(), gallery())
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from reactpy import component, html

__all__ = ["gallery", "profile"]


@component
def profile():
    return html.img({"src": "https://i.imgur.com/QIrZWGIs.jpg", "alt": "Alan L. Hart"})


@component
def gallery():
    return html.section(
        html.h1("Amazing scientists"),
        profile(),
        profile(),
        profile(),
    )

Now gallery.py publishes both components:

  • gallery.py:
    • Lists gallery and profile in __all__.
  • app.py:
    • Imports both gallery and profile from gallery.py.
    • Renders each of them.

Recap

You've learned:

  • What a root component module is, and that it depends on your executor
  • How to import a component from another file
  • How ReactPy expresses public and private components with __all__ and a leading underscore
  • How to export multiple components from the same file

Next Steps

Now that your components can live in separate files, continue to Passing Props to a Component to make them configurable.

Authors: Archmonger