Reactium App Foundation Reactium Guides 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:
Copy 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:
Copy 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
Copy 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!
Copy 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:
Copy 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
Copy .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:
Home.jsx About.jsx
Copy 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;
Copy import {
useSyncState,
useHookComponent,
} from '@atomic-reactor/reactium-core/sdk';
import React from 'react';
/**
* -----------------------------------------------------------------------------
* Component: About
* -----------------------------------------------------------------------------
*/
export const About = ({ className }) => {
const Nav = useHookComponent('Nav');
const state = useSyncState({ content: 'About' });
return (
<div className={className}>
<Nav />
<h1>{state.get('content')}</h1>
<p>This is the About page.</p>
</div>
);
};
About.defaultProps = {
className: 'about',
};
export default About;
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!
Copy 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.
AppParent.jsx _reactium-style-organisms-AppParent.scss Home.jsx About.jsx _reactium-style-molecules-Nav.scss
Copy 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!
Copy .main {
padding: 50px;
&-nav, &-content {
border-bottom: 1px solid black;
}
&-content {
padding: 20px 0;
}
}
Copy import { useSyncState } from '@atomic-reactor/reactium-core/sdk';
import React from 'react';
/**
* -----------------------------------------------------------------------------
* Component: Home
* -----------------------------------------------------------------------------
*/
export const Home = ({ className }) => {
const state = useSyncState({ content: 'Home' });
return (
<div className={className}>
<h1>{state.get('content')}</h1>
<p>This is the Home page.</p>
</div>
);
};
Home.defaultProps = {
className: 'home',
};
export default Home;
Copy import { useSyncState } from '@atomic-reactor/reactium-core/sdk';
import React from 'react';
/**
* -----------------------------------------------------------------------------
* Component: About
* -----------------------------------------------------------------------------
*/
export const About = ({ className }) => {
const state = useSyncState({ content: 'About' });
return (
<div className={className}>
<h1>{state.get('content')}</h1>
<p>This is the About page.</p>
</div>
);
};
About.defaultProps = {
className: 'about',
};
export default About;
Copy .nav {
display: flex;
a {
padding: 10px 20px;
&,
&:visited,
&:hover,
&:active {
text-decoration: none;
}
&,
&:visited {
color: gray;
}
&:hover,
&.active {
color: white;
background: gray;
}
}
}
Final Simple SPA