Skip to main content

Using React in Foundation for Sites

This post was the precursor to the Foundation-React Template.

React and Foundation are two different web UI frameworks addressing different needs. They evolve differently. Both of them are powerful on their own accord. Fusing them together may create superpower.

We will walk through the process of adding React into Foundation. We will start by installing both Foundation and React through command line interface (CLI). Then we will create a simple Todo web app. Along the way we will highlight the development process. But before all that, let us summarize React and Foundation. The details can be found at their respective websites. Both of them are well documented.

React is a run-time UI rendering engine. It renders dynamic UI elements in its own fast virtual DOM, and only update necessary changes to the slow browser DOM. This behaves like a double buffering DOM which makes any UI update feels fast. React wraps a UI rendering script in a component. A React component can be bound to a data set where any changes to the data will trigger UI re-rendering. The nature of the React script simplifies the process. We know that Javascript can be embedded into HTML. On the other hand, React's JSX notation allows HTML elements to be embedded in Javascript. This makes writing UI rendering script easier and more readable. We can treat a JSX script as a UI template wrapped as a component. The JSX script will then be preprocessed and fed into the run-time rendering engine.

Foundation is a UI tool-chain with style. Foundation is a responsive front-end framework. It enables modular design. It simplifies scripting with preprocessing such as for SASS which in the website says a "CSS with superpowers". It automates many development tasks using webpack, gulp, nodejs, etc. However, the Foundation's responsive front-end framework is not unique on the Internet. There are many other competing frameworks. The strength of Foundation is in its tool-chain which improves development process.

Adding React to Foundation will change the game. The days of plain scripting for HTML, CSS and Javascript to develop front-ends have long gone. The days of UI frameworks are also numbered. It is no more about scripting. Now, it is about productive development process which involves automation. We will never stop scripting but what we want is that all best practices to be automated.

Installation

There are many ways to install Foundation. Let us do it with Foundation CLI. We are doing Javascript so it is ironic if we do not have node with npm on our development machine. Node has many uses other than serving application back-ends.

Let's install Foundation CLI:
$ npm install --global foundation-cli
# or sudo npm install --global foundation-cli
And create a new Foundation project:
$ foundation new
After you selected "Foundation for Sites" and called the project "todo", Foundation CLI will ask you which template you want to use. Choose "Basic template". And wait for it to setup the new project and download dependencies.

Then change to the newly created todo folder and run foundation watch:
$ cd todo
$ foundation watch
It will run a local server hosting the new default app and launch it in your browser at http://localhost:3000/. We are going to replace the default app with our todo app. But before that, we need to install React. Stop foundation watch with ctrl-c. We will run it again later.

The foundation watch is not merely a local server. It is a development server. It monitors all source files looking for changes. If there is a change in a source file then it will trigger preprocessors and other development automation tools against all source files. The distribution files will be updated. And the browser will be refreshed. These free developer from many repetitive tasks and save a lot of development time. Foundation makes used of gulp to do the job. So we will extend gulp for React.

Install React:
$ npm install react react-dom

React uses babel preset to preprocess jsx files into standard Javascript. So we need to include babel into gulp together with the React's babel preset.

Install Gulp Babel for React:
$ npm install --save-dev gulp-babel @babel/core @babel/preset-env @babel/preset-react

JSX

We are going to prepare jsx preprocessor which will be handled by babel-preset-react. And we want the jsx preprocessor to be automated by gulp.

Foundation uses gulp to automate sass preproccessor and monitor file changes during development. On any source file changed gulp will rebuild the project and refresh the browser. The configuration is done in the gulpfile.js.

Open the gulpfile.js and insert the following line after require('gulp'):
var babel = require('gulp-babel');
And then insert the following code before function serve():
function react() {
  return gulp.src('jsx/*.jsx')
    .pipe(babel({
      presets: ['@babel/env', '@babel/react']
    }))
    .pipe(gulp.dest('js'))
    .pipe(browserSync.stream());
};
The code above tells gulp to monitor all jsx files in the jsx folder. When there is a change in a file then pass the file to the babel React preset to preprocess it into a js file, and copy the js file into the js folder, and then notify the browser to refresh.

Insert the following line within function serve() and before gulp.watch("*.html"):
  gulp.watch("jsx/*.jsx", react);
And insert the following line after gulp.task('sass', sass) :
gulp.task('react', react);
And insert 'react' to the last two lines so that they look like the following:
gulp.task('serve', gulp.series('sass', 'react', serve));
gulp.task('default', gulp.series('sass', 'react', serve));
The final gulpfile.js will look like the following:
var gulp          = require('gulp');
var babel         = require('gulp-babel');
var browserSync   = require('browser-sync').create();
var $             = require('gulp-load-plugins')();
var autoprefixer  = require('autoprefixer');

var sassPaths = [
  'node_modules/foundation-sites/scss',
  'node_modules/motion-ui/src'
];

function sass() {
  return gulp.src('scss/app.scss')
    .pipe($.sass({
      includePaths: sassPaths,
      outputStyle: 'compressed' // if css compressed **file size**
    })
      .on('error', $.sass.logError))
    .pipe($.postcss([
      autoprefixer({ browsers: ['last 2 versions', 'ie >= 9'] })
    ]))
    .pipe(gulp.dest('css'))
    .pipe(browserSync.stream());
};

function react() {
  return gulp.src('jsx/*.jsx')
    .pipe(babel({
      presets: ['@babel/env', '@babel/react']
    }))
    .pipe(gulp.dest('js'))
    .pipe(browserSync.stream());
};

function serve() {
  browserSync.init({
    server: "./"
  });

  gulp.watch("scss/*.scss", sass);
  gulp.watch("jsx/*.jsx", react);
  gulp.watch("*.html").on('change', browserSync.reload);
}

gulp.task('sass', sass);
gulp.task('react', react);
gulp.task('serve', gulp.series('sass', 'react', serve));
gulp.task('default', gulp.series('sass', 'react', serve));

Index.html

Let's clean up the index.html file to look like the following:
<!doctype html>
<html class="no-js" lang="en">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Todo</title>
    <link rel="stylesheet" href="css/app.css">
  </head>
  <body>

    <div class="grid-x grid-padding-x">
      <div class="cell">
        <div id="todos-example"></div>
      </div>
    </div>

    <script src="node_modules/jquery/dist/jquery.js"></script>
    <script src="node_modules/what-input/dist/what-input.js"></script>
    <script src="node_modules/foundation-sites/dist/js/foundation.js"></script>
    <script src="js/app.js"></script>
  </body>
</html>
In the code above we inserted the React todo app placeholder in a div with the id todos-example. And we wrapped the placeholder inside a Foundation grid cell.

Now add react and react-dom references to the bottom of index.html before the line with "js/app.js" with the following lines:
    <script src="node_modules/react/umd/react.development.js"></script>
    <script src="node_modules/react-dom/umd/react-dom.development.js"></script>

App.jsx

Create jsx folder and create app.jsx file in the folder. Add the following React code to the app.jsx file:
$(document).foundation();

class TodoApp extends React.Component {
  constructor(props) {
    super(props);
    this.state = { items: [], text: '' };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  render() {
    return (
      <div>
        <h3>My TODO</h3>
        <TodoList items={this.state.items} />
        <form onSubmit={this.handleSubmit}>
          <label htmlFor="new-todo">
            What needs to be done?
          </label>
          <input
            type="text"
            id="new-todo"
            onChange={this.handleChange}
            value={this.state.text}
          />
          <button type="submit" class="button">
            Add #{this.state.items.length + 1}
          </button>
        </form>
      </div>
    );
  }

  handleChange(e) {
    this.setState({ text: e.target.value });
  }

  handleSubmit(e) {
    e.preventDefault();
    if (!this.state.text.length) {
      return;
    }
    const newItem = {
      text: this.state.text,
      id: Date.now()
    };
    this.setState(state => ({
      items: state.items.concat(newItem),
      text: ''
    }));
  }
}

class TodoList extends React.Component {
  render() {
    return (
      <ul>
        {this.props.items.map(item => (
          <li key={item.id}>{item.text}</li>
        ))}
      </ul>
    );
  }
}

ReactDOM.render(
  <TodoApp />,
  document.getElementById('todos-example')
);
Notice that Foundation is initialized on the first line.

That's all. Let's run foundation watch again to launch our todo app.
$ foundation watch


Todo is a simple app that uses a single jsx file. A bigger app will have many modules in many jsx files. Loading many javascript files into a web app is not a good practice. Each time we create a jsx file we will have to include the generated js file into the index.html file. The best approach is to pack all generated js files into a single js file. That will be another discussion.

Now we know how to use React in Foundation for Sites. The next logical step is to create a Foundation-React template so that we don't have to go through most or all of these steps again when we want to create another application. That also will be another discussion.

Comments

Popular posts from this blog

Setting Up PyScripter for Quantum GIS

PyScripter is a general purpose Python Integrated Development Environment (IDE). Quantum GIS (QGIS) is a desktop GIS application that can be extended with Python plugins. Both are open source softwares. We intend to use PyScripter as an IDE to build QGIS Python plugin. We are using PyScripter 2.4.1.0 and QGIS 1.6.0 in Windows. PyScripter does not come with Python. On the other hand, QGIS is built in with Python. Thus, we will setup up PyScripter to use the build in Python in QGIS. We assume both PyScripter and QGIS are already installed. Preparing PyScripter batch file We assume that QGIS is installed in C:\OSGeo4W\ folder and PyScripter is installed in C:\Program Files\PyScripter\ . 1. Copy qgis.bat in C:\OSGeo4W\ bin to pyscripter.bat 2. Edit pyscripter.bat to remove the last line that read something like this start "Quantum GIS" /B "%OSGEO4W_ROOT%"\apps\qgis\bin\qgis.exe %* and replace it with this in one line Start "PyScripter" /B "C:\Progr

Sending Emails via SMTP

msmtp  requires a minimal setup for sending emails via SMTP compared to sendmail. Here is a configuration for you to send emails from a web host to an external SMTP server. Prior to doing that, you must check whether there is a clear communication channel between your web host and the SMTP server. You can use Telnet . Set up msmtp You are going to set msmtp as an MTA . Hence, you need to remove all other MTAs such as postfix and sendmail: $ sudo apt-get --purge autoremove postfix sendmail Install msmtp and related utilities: $ sudo apt-get install msmtp msmtp-mta mailutils Configure msmtp: $ sudo nano /etc/msmtprc # Set default values for all following accounts. defaults # Use the mail submission port 587 instead of the SMTP port 25. port 587 # Always use TLS. tls on # Set a list of trusted CAs for TLS. The default is to use system settings, but # you can select your own file. tls_trust_file /etc/ssl/certs/ca-certificates.crt # The SMTP server account mx host mail.mx.example

fatal: Couldn't find remote ref master

If you are using Github then  master is now known as main . Whatever you want to do with a master must now be referred to a main . If you search for this error message on the Internet then you will encounter with a lot of old discussions on how to set up your master properly which is probably not what you are looking for. The master  is your problem. Rename it to main . I wrote Git My Way about two years ago. Today I created another Github repository. I got this  "fatal: Couldn't find remote ref master"  error message when I wanted to sync the new repo for the first time with my notebook using the notes I wrote in the blog. All the discussions around the error message I found on the Internet were perplexing. Then I recalled that Github had renamed master to main  due to the master-slave connotation. We always have a master copy of a code, never a slave copy. Now suddenly a word context has been diminished for good. What is going to happen to the existing vast documen