Alex Page

Intro to React

for government

Basics

Render react to HTML

Set up package.json

package.json

"scripts": {
  "build": "babel src --out-dir dist --watch"
},
"dependencies": {
  "babel-cli": "^6.24.1",
  "babel-preset-es2015": "^6.24.1",
  "babel-preset-react": "^6.24.1",
  "babel-preset-stage-0": "^6.24.1"
  "react": "^15.6.1",
  "react-dom": "^15.6.1"
}

babel.rc

"presets": [
  "es2015",
  "stage-0",
  "react"
]

React components

// Import react
import React from 'react';

// Create an element (this is JSX)
const exampleElement = React.createElement( "h1", null, "Hello world" );

// Show the output in nodeJS
console.log( exampleElement );
{ 
  '$$typeof': Symbol(react.element),
  type: 'h1',
  key: null,
  ref: null,
  props: { children: 'Hello world' },
  _owner: null,
  _store: {} 
}

React to HTML

// Import react and react-dom/server
import React from 'react';
import ReactDomServer from 'react-dom/server';

// Create an example component
const ExampleComponent = () => {
    return <h1>Hello world</h1>;
}

// Turn the component into static HTML
const exampleMarkup = ReactDomServer.renderToStaticMarkup( <ExampleComponent /> );

// Log the HTML
console.log( exampleMarkup );
<h1>Hello world</h1>

React to HTML with properties

// Import react
import React from 'react';
import ReactDomServer from 'react-dom/server';

// Instance of the component
const ExampleComponent = ( props ) => {
    return <h1 className="site-title">Hello { props.name }</h1>;
}

// Turn the component
const example = ReactDomServer.renderToStaticMarkup(
    <ExampleComponent name="CanberraJS" />
);

// Renders the JSX from before
console.log( example );
<h1 class="site-title">Hello CanberraJS</h1>

Seperating content and components

content/homepage.json

{
  "component": "page.js",
  "properties": {
    "title": "Home - Hello CanberraJS",
    "content": "Hello world"
  }
}

components/page.js

import React from "react";

export default ( page ) => (
  <html>
  <head>
    <title>{ page.title }</title>
  </head>
  <body>{ page.content }</body>
  </html>
);

React to HTML pipeline

src/index.js

import Path from 'path';
import { RenderSite } from './render';
import SiteContent from '../content/homepage.json';

const siteComponent = Path.resolve( __dirname, '../components/' + SiteContent.page.component );
const siteProperties = SiteContent.page.properties;

RenderSite( './site', siteComponent, siteProperties );

src/render.js

export const RenderSite = ( location, siteComponent, siteProperties ) => {

  return PreRender( location )
    .then( ( ) => ReadFile( siteComponent ) )
    .then( ( contents ) => RequireBabelfy( contents ) )
    .then( ( component ) => ReactRender( component.default, siteProperties ) )
    .then( ( renderedComponent ) => CreateFile( `${location}/index.html`, renderedComponent ) )
    .catch( ( error ) => console.log( error ) );
};

RequireBabelify and ReactRender

src/render.js

export const RequireBabelfy = ( source ) => {

    const registerObj = {
      presets: [ 
        'babel-preset-es2015', 
        'babel-preset-stage-0', 
        'babel-preset-react' 
      ]
    };

    const transpiledSource = require("babel-core").transform( source, registerObj );

    return RequireFromString( transpiledSource.code );
};

export const ReactRender = ( code, properties ) => {
  let component = React.createElement( code, properties );
  return ReactDomServer.renderToStaticMarkup( component );
};

🐙🔔 Cuttlebelle

npm i cuttlebelle

package.json

"cuttlebelle": {
  "folder": {
    "site": "site/",
    "content": "content",
    "code": "src/react",
    "assets": "src/assets"
  },
},

Markdown + Yaml + React = HTML

/content/

.
├── index
│   ├── index.yml
│   └── partial1.md
├── page1
│   ├── index.yml
├── page2
│   ├── index.yml
│   └── partial1.md
└── shared
    └── component1.md

/site/

.
├── index.html
├── page1
│   ├── index.html
└── page2
    └── index.html

content/index/index.yml

layout: page
title: Homepage
header: /_shared/header.md
main:
  - main.md

src/react/page.js

import React from "react";

export default ({ title, main }) => (
  <html>
    <head>
      <title>{ title }</title>
    </head>
    <body>
      { header }
      <main>{ main }</main>
    </body>
  </html>
);

{ header }

content/_shared/header.md

---
layout: header
headline: First post
sub: Clear content separation
---

src/react/header.js

import React from "react";

export default ({ headline, sub }) => (
  <header>
    <h1 className="header__headline">{ headline }</h1>
    {
      sub
        && <p className="header__sub">{ sub }</p>
    }
  </header>
);

{ main }

content/index/main.md

---
layout: main
headline: First post
---

**Hello world**

src/react/main.js

import React from "react";

export default ({ _body, headline }) => (
  <article>
    <h2>{ headline }</h2>
    <div className="body-text">{ _body }</div>
  </article>
);

Result

site/index.html

<!DOCTYPE html>
<html>
<head>
  <title>Homepage</title>
</head>

<body>
  <main>
    <header>
      <h1 class="header__headline">First post</h1>
      <p class="header__sub">Clear content separation</p>
    </header>
    <article>
      <h2>First post</h2>
      <div class="body-text"><strong>Hello world</strong></div>
    </article>
  </main>
</body>

</html>

How it works

Questions?

🐙🔔 Cuttlebelle

⭐️ Star it on Github Cuttlebelle