Creating a Simple Single Page Web App (SPA)

The Reactium foundational framework can be used to build a stand-alone simple Web App. Need a quick React app with routed components, here's how you do it!

TL;DR - from the command line, run:

mkdir myapp
cd myapp

npx reactium init

[ARCLI] > Initialize what type of project?:  (Use arrow keys)
 Reactium (Web Application) 
  Actinium (Web API) 

# Delete the default component
rm -rf src/app/components/Welcome

# Create Your Home Page!
npx reactium component

[ARCLI] > Select directory:  src/app/components
 src/app/components
  src/app/components/common-ui
  
[ARCLI] > Component Name:  Home

[ARCLI] > Route:  /

[ARCLI] > Reactium Hooks?:  Yes

[ARCLI] > Domain file?:  Yes

[ARCLI] > Stylesheet?:  Yes

[ARCLI] > Select stylesheet type:  
  base 
  atoms 
  molecules 
 organisms 
  overrides 
  default 
  mixins
  
[ARCLI] > Preflight checklist:
{
  "destination": "src/app/components/Home",
  "name": "Home",
  "route": "['/']",
  "hooks": true,
  "domain": true,
  "style": true,
  "styleType": "_reactium-style-organisms.scss",
  "className": "home",
  "index": true
}

[ARCLI] > Proceed?:  (y/N) y

npm run local  

That's it. You should be looking at a running simple app, with your Home component running on http://localhost:3000

Creating A Page

Let's break down what's happening with the previous reactium command. After proceeding, your scr/app directory should look something like this:

src/app
├── components
│   ├── Home
│   │   ├── Home.jsx
│   │   ├── reactium-domain-home.js <- defines the unique namespace of our component
│   │   ├── reactium-hooks-home.js <- Reactium plugin hooks go here
│   │   ├── reactium-route-home.js <- Defines the Route where this component renders in the front-end
│   │   └── _reactium-style-organisms-Home.scss <- Styles go here
└── main.js <- The main entry point of the app (usually no modifications needed)

Create a Second Page

npx reactium component

[ARCLI] > Select directory:  src/app/components
 src/app/components
  src/app/components/common-ui
  
[ARCLI] > Component Name:  About

[ARCLI] > Route:  /about

[ARCLI] > Reactium Hooks?:  Yes

[ARCLI] > Domain file?:  Yes

[ARCLI] > Stylesheet?:  Yes

[ARCLI] > Select stylesheet type:  
  base 
  atoms 
  molecules 
 organisms 
  overrides 
  default 
  mixins
  
[ARCLI] > Preflight checklist:
{
  "destination": "src/app/components/About",
  "name": "About",
  "route": "['/about']",
  "hooks": true,
  "domain": true,
  "style": true,
  "styleType": "_reactium-style-organisms.scss",
  "className": "about",
  "index": true
}

[ARCLI] > Proceed?:  (y/N) y

Single Page Application Navigation

You already have a React single-page application started.

Let's create a navigation component and render it on both pages!

npx reactium component

[ARCLI] > Select directory:  common-ui
 src/app/components/common-ui

[ARCLI] > Component Name:  Nav

[ARCLI] > Route:
[ARCLI] > Reactium Hooks?:  (Y/n)  Yes
[ARCLI] > Domain file?:  (Y/n)  Yes

[ARCLI] > Stylesheet?:  (Y/n) Yes
  variables 
  base 
  atoms 
 molecules 
  organisms 
  overrides 
  default 
(Move up and down to reveal more choices)

[ARCLI] > Preflight checklist:

{
  "destination": "src/app/components/common-ui/Nav",
  "name": "Nav",
  "route": "[]",
  "hooks": true,
  "domain": true,
  "style": true,
  "styleType": "_reactium-style-molecules",
  "className": "nav",
  "index": true
}

[ARCLI] > Proceed?:  (Y/n) Yes

Ok, let's modify our Nav component:

common-ui/Nav/Nav.jsx
import React from 'react';
import { NavLink } from 'react-router-dom';

/**
 * -----------------------------------------------------------------------------
 * Component: Nav
 * -----------------------------------------------------------------------------
 */
export const Nav = ({ className }) => {
    return (
        <nav className={className}>
            <NavLink to='/' exact={true} activeClassName='active'>
                Home
            </NavLink>
            <NavLink to='/about' activeClassName='active'>
                About
            </NavLink>
        </nav>
    );
};

Nav.defaultProps = {
    className: 'nav',
};

export default Nav;

Let's also add some sassy styles for Nav:

common-ui/Nav/_reactium-style-molecules-Nav.scss
.nav {
    display: flex;
    flex-direction: column;
    padding: 20px;

    a {
      &, &:visited {
        color: gray;
      }
      &:hover, &.active {
        color: black;
      }
    }
}

Great, now let's include the Nav in both the Home page and the About page:

import {
    useSyncState,
    useHookComponent,
} from '@atomic-reactor/reactium-core/sdk';
import React from 'react';

/**
 * -----------------------------------------------------------------------------
 * Component: Home
 * -----------------------------------------------------------------------------
 */
export const Home = ({ className }) => {
    const Nav = useHookComponent('Nav');
    const state = useSyncState({ content: 'Home' });

    return (
        <div className={className}>
            <Nav />
            <h1>{state.get('content')}</h1>
            <p>This is the Home page.</p>
        </div>
    );
};

Home.defaultProps = {
    className: 'home',
};

export default Home;

Great, Now we are SPA Routing!

But wait, does that mean I have to have common elements like the Nav on every routed page?

Let's create an AppParent component to be the "window dressing" for our app!

npx reactium component

[ARCLI] > Select directory:  common-ui
 src/app/components/common-ui

[ARCLI] > Component Name:  AppParent

[ARCLI] > Route:
[ARCLI] > Reactium Hooks?:  (Y/n)  Yes
[ARCLI] > Domain file?:  (Y/n)  Yes

[ARCLI] > Stylesheet?:  (Y/n) Yes
  variables 
  base 
  atoms 
  molecules 
 organisms 
  overrides 
  default 
(Move up and down to reveal more choices)

[ARCLI] > Preflight checklist:

{
  "destination": "src/app/components/common-ui/AppParent",
  "name": "AppParent",
  "route": "[]",
  "hooks": true,
  "domain": true,
  "style": true,
  "styleType": "_reactium-style-organisms",
  "className": "appparent",
  "index": true
}

[ARCLI] > Proceed?:  (Y/n) Yes

Let's move the Nav to the AppParent component, and add some common page structure to the app.

import { useHookComponent } from '@atomic-reactor/reactium-core/sdk';
import React from 'react';

/**
 * -----------------------------------------------------------------------------
 * Component: AppParent
 * -----------------------------------------------------------------------------
 */
export const AppParent = ({ className, children }) => {
    const Nav = useHookComponent('Nav');
    const Footer = useHookComponent('Footer');
    return (
        <main className={className}>
            <aside className='main-nav'>
                <Nav />
            </aside>
            <section className='main-content'>{children}</section>
            <footer className='main-footer'>
                <Footer />
            </footer>
        </main>
    );
};

AppParent.defaultProps = {
    className: 'appparent main',
};

export default AppParent;

Note that the Footer component need not actually already exist. If someone creates one with that name, it will just show up!

By creating an AppParent component that returns props.children, it will automatically take the place of the component in reactium-core. Registered components are overridden! A good thing!

Final Simple SPA

Last updated