React on Node for Beginners: Build a basic Macintoshes App
The app you will be building here is pretty generic (on purpose for simplicity). It takes from a JS file with a JSON set in it as a fake database as a starting point for your content. You could always connect this to a real database later it is a proof of concept.In our databank as it is referred to in this tutorial we have a list of our favorite Macintosh computers throughout time. We then have this list displaying via react on port 8080 via a node server.
$ mkdir your_app && cd your_app
$ npm init (press return multiple times
$ touch webpack.config.js
$ mkdir -p src/static src/static/css src/components src/data
$ touch src/static/index.html
$ touch src/data/databank.js
Everything starts out nice and basic, lets go ahead and create an index.html
file that will serve our forthcoming webpack.js
file.<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Best Macs - A Universal JavaScript demo application with React</title>
<link rel="stylesheet" href="/css/app.css">
</head>
<body>
<div id="main"></div>
<script src="/js/bundle.js"></script>
</body>
</html>
Now what we are doing is making our JSON
file that will serve as a database, we’ll call it databank
, because its not-quite-a-database but it’s good enough.// src/static/databank.js
const databank = [
{
'id': 'mactwo-ci',
'name': 'Macintosh IIci',
'country': 'united states',
'birth': '1989',
'price': '$6269',
'cpu': 'moto 68030 25mhz',
'image': 'https://en.wikipedia.org/wiki/File:Macintosh_IIci.png',
'link': 'https://en.wikipedia.org/wiki/Macintosh_IIci'
},
{
'id': 'mactwo-fx',
'name': 'Macintosh IIfx',
'country': 'united states',
'birth': '1990',
'price': '$9900',
'cpu': 'moto 68030 40mhz',
'ram': '4 MB',
'max-ram': '128 MB',
'image': 'https://en.wikipedia.org/wiki/File:Macintosh_IIfx.png',
'link': 'https://en.wikipedia.org/wiki/Macintosh_IIfx'
},
{
'id': 'macse-30',
'name': 'Macintosh SE30',
'country': 'united states',
'birth': '1989',
'price': '$4369',
'cpu': 'moto 68030 16mhz',
'ram': '1 MB',
'max-ram': '128 MB',
'image': 'https://en.wikipedia.org/wiki/File:Macintosh_IIfx.png',
'link': 'https://en.wikipedia.org/wiki/Macintosh_SE/30'
},
];
export default databank;
Next we create the DataPreview Component. For our React App. Think of this as the list of things from the databank.js
which is told to the IndexPage.js
(forthcoming).// src/components/DataPreview.js
// I preview your data from your databank.js so your IndexPage.js knows what to show
import React from 'react';
import { Link } from 'react-router';
export default class DataPreview extends React.Component {
render() {
return (
<Link to={`/hardware/${this.props.id}`}>
<div className="data-preview">
<h2 className="name">{this.props.name}</h2>
</div>
</Link>
);
}
Now we have all the dependencies that the index page will need let’s go out and do the index page. Keep in mind this is the react jS index page.// the almighty IndexPage.js
import React from 'react';
import DataPreview from './DataPreview'
import databank from '../data/databank';
export default class IndexPage extends React.Component {
render() {
return (
<div className="home">
<div className="data-selector">
{databank.map(databankData => <DataPreview key={databankData.id} {...databankData} />)}
</div>
</div>
);
}
}
Now it’s time to think about your navbar and the template for your entire app. There is no way we are doing this by hand. Let’s be thankful that react JS is smart enough to take the objects in our databank.JS fil in our navbar for us.The final file we will do is our template. We will reference our nav. bar and our index.JS in this file. And finally we will do the now bar or menu file.
// components/NavBar.js
import React from 'react';
import { Link } from 'react-router';
import databank from '../data/databank';
export default class NavBar extends React.Component {
render() {
return (
<nav className="data-menu">
{databank.map(menuData => {
return <Link key={menuData.id} to={`/hardware/${menuData.id}`} activeClassName="active">
{menuData.name}
</Link>;
})}
</nav>
);
}
}
The Template Component of our ReactJS app is very self explanatory so we are kind of thrown a bone here.// components/Template.js
export default class Template extends React.Component {
render() {
return (
<div className="app-container">
<header>
<Link to="/">
<img className="logo" src="/img/logo-apple-logo.png"/>
</Link>
</header>
<div className="app-content">{this.props.children}</div>
<footer>
<p>
This is a demo app to showcase universal rendering and routing with <strong>React</strong> and <strong>Express</strong>.
</p>
</footer>
</div>
);
}
}
There will be two more pages. A computers page which will display the info on all of the parts of your databank for each object. And you need to finesse your routes.JS page in order to tell your react application about all of these nifty things that you have just created underneath the components folder.So let’s get the computers page. Clearly if your app is something other than computers you will insert the noun which you are listing from your databank instead of computers so it will not be confusing.
//components/ComputerPage.js
// src/components/AthletePage.js
import React from 'react';
import { Link } from 'react-router';
import NavBar from './NavBar';
import databank from '../data/databank';
export default class ComputerPage extends React.Component {
render() {
const id = this.props.params.id;
const data = databank.filter((databank) => databank.id === id)[0];
if (!data) {
return <div> not found dude :( </div>;
}
return (
<div className="computer-full">
<NavBar/>
<div className="computer">
<div className="item-container">
<h2 className="name">Welcome to the {data.name}</h2>
</div>
</div>
<div className="navigateBack">
<Link to="/">« Back to the index</Link>
</div>
</div>
);
}
}
One more thing is that there will be an out Apple routes component file to which she will import your routes JS file. While it was rather generic and basically just set up your environment for your react JS application. One important thing to note is the line about importing the reactor router. You will either specify hashhistory or browserhistory based on whether or not you are running in development or production respectively.Remember you will put this file in your components directory.
// src/components/AppRoutes.js
import React from 'react';
import { Router, hashHistory } from 'react-router';
import routes from '../routes';
export default class AppRoutes extends React.Component {
render() {
return (
<Router history={hashHistory} routes={routes} onUpdate={() => window.scrollTo(0, 0)}/>
);
}
}
Let’s get to your regular routes page. This one is way more fun, it’s where everything comes together. If you are familiar with the rails is should bring them back some serious memories. Although it is not as strict as a rails app will be with routes.
Pay attention! This one goes one directory level up – not in your components directory.
// src/routes.js
import React from 'react'
import { Route, IndexRoute } from 'react-router'
import Template from './components/Template';
import IndexPage from './components/IndexPage';
import ComputerPage from './components/ComputerPage';
// import NotFoundPage from './components/NotFoundPage';
const routes = (
<Route path="/" component={Template}>
<IndexRoute component={IndexPage}/>
<Route path="hardware/:id" component={ComputerPage}/>
</Route>
);
export default routes;
You know how in a node JS application you will have your server.JS file? Well since this is a reactive application you will need a client.JS file as an entry point for your app to run. Remember this will go in the same directory as your routes.JS file.// src/client.js
import React from 'react';
import ReactDOM from 'react-dom';
import AppRoutes from './components/AppRoutes';
window.onload = () => {
ReactDOM.render(<AppRoutes/>, document.getElementById('main'));
};
Here is the dread of every react developer setting up your web pack.Jazz file. Now I will tell you an important secret. What you want to do here is make sure that when you are developing to run web pack in a watching mode. In order to do that after paste the following in your webpack.config.js
way back in your application's root folder
, run a $ webpack -w
, or you will have to recompile your sources
every single time, not fun:// webpack.config.js
const webpack = require('webpack');
const path = require('path');
module.exports = {
entry: path.join(__dirname, 'src', 'client.js'),
output: {
path: path.join(__dirname, 'src', 'static', 'js'),
filename: 'bundle.js'
},
module: {
loaders: [{
test: path.join(__dirname, 'src'),
loader: ['babel-loader'],
query: {
cacheDirectory: 'babel_cache',
presets: ['react', 'es2015']
}
}]
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV)
}),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
compress: { warnings: false },
mangle: true,
sourcemap: false,
beautify: false,
dead_code: true
})
]
};
If you are reading this congratulations.
First of all you need to level-up your webpack
game. Let's run Webpack in Watch mode so that when we make changes to any of our JS asset's webpack will recompile on the fly, do this from the application's root directory.
$ webpack -w
The last thing you want to do is fire up your Application via a HTTP-server
Node module you do that like so from your application root directory
:$ node_modules/.bin/http-server src/static
A couple of beginner notes to watch:- watch your directory structure
- your syntax may be so messed up that it crashes
$ webpack -w
if you do watch yourwebpack error messages
and restart$ webpack -w
JSON notation can be tricky
, use a good editor and watch for errors there, plus hyphens(-)
are going to pwn your dataset if they are in thekey
position of yourkey-value
pairs
No comments:
Post a Comment