Diving Headfirst into ReactJS
ReactJS is the View in a MVC (and it is a library). It could be combined with frameworks (AngularJS, Ember, Meteor) or other Javascript libraries (Knockout). It could be used with Flux (data flow pattern).
Transpilers (Babel, Traceur) are used to generate a baseline ES5 code.
Component Specification
ReactJS has new built-in set of methods and properties for several purposes: debugging (displayName, propTypes), setting initial data (getInitialState, getDefaultProps), component life cycle (componentDidMount, etc).
Props and States
They are component data instantiated: outside (props), inside (states).
Props must not be modified and they are immutable. Stored in this.props. Set initial props with getDefaultProps(). If there is no initial prop React will throw an error (property does not exist).
State is store in this.state. Set defult state with setInitialState(). React will throw an error if state variable does not exist. Every time the state changes, ReactJS responds by re-rendering the output.
render
It is mandatory. It could return null or false to indicate no rendering. It should return a single child element.
statics
Define static methods which do not have access to props and state.
const App = React.createClass({
statics: {
myMethod: (foo) => {
return foo == 'bar';
}
},
render() {
return null;
}
});
console.log(App.myMethod('bar')); // true
propTypes
It is optional and indicates validation. It could define custom validators or use built-in validators.
propTypes: {
myOptionalObject: React.PropTypes.object,
aRequiredString: React.PropTypes.string.isRequired,
anOptionalNumber: React.PropTypes.number,
aValueOfAnyKind: React.PropTypes.any,
customProp: function(props, propName, componentName) {
if (!/matchme/.test(props[propName])) {
return new Error('Validation failed!');
}
}
}
displayName
Set it automatically. displayName: "My component Name"
Life Cycle Methods
componentDidMount
Run directly after the component has been rendered for the first time. You have access to the current contents of states and props in this method, but take care to never run setState in here, as that will trigger an endless update loop. It's worth noting that if you're making a server-side app, this component will not be called. In this case, you'll have to rely on componentWillMount instead.
componentWillMount
Access to the current component's state and props; it's safe to run setState here. Executed on both server-side and client-side apps.
shouldComponentUpdate
Invoked whenever the component receives new props or a change in state occurs.
componentWillReceiveProps
Compare the incoming props and can be used as an opportunity to react to a prop transition before the render method is called. Calling setState here, an additional re-render will not be triggered. It's not called for the initial render. To access incoming props: componentWillReceiveProps(object nextProps)
There is not a method to detect changes in state. If you want to run setState based on a prop change, use componentWillReceiveProps instead.
componentWillUpdate
This method is executed before the rendering, when the component receives new props or states but not on the initial render. Use it as: componentWillUpdate(object nextProps, object nextState)
. Calling setState here will trigger an endless loop.
componentDidUpdate
Execute functions after the component has been updated
componentWillUnmount
Execute functions before the component is unmounted from the DOM.
Virtual DOM
You cannot look for changes in the DOM and make changes directly. Instead, you need to attach a reference named refs
to the elements you want to target. You can do this by adding ref="myReference"
to your element. Used as: React.findDOMNode(this.refs. myReference)
Synthetic event handlers
Whenever you call an event handler within ReactJS, they are passed an instance of SyntheticEvent
instead of the native event handler. The events are triggered in a bubbling phase. This means that the event is first captured down to the deepest target and then propagated to outer elements. Sometimes, you may find yourself wanting to capture the event immediately. In such cases, adding Capture
behind the event can achieve this. For instance, to capture onClick immediately, use onClickCapture and so on. You can stop propagation by callingevent.stopPropagation()
or event.preventDefault()
where appropriate.
More information about events: https://facebook.github.io/react/docs/events.html
Composition
Composition is the act of combining things together to make more complex things and then putting these things together to make even more complex things, and so on.
const HelloWorld = require("./helloworld.jsx");
const HelloWorld = require("./helloworld.jsx");
render() {
return <div>
<HelloWorld />
</div>
}
This is one of the many compelling reasons for choosing ReactJS.
Developing with modern frontend tools
NodeJS and npm are always the best tools mandatory for any Javascript project. You write modular code that is self-contained, and you always specify your dependencies up front. Easy to read and understand code and allows easy dependency injection when writing tests.
Browserify, Browser-sync, Babelify and Webpack
They are the most popular tools for assembling modular code. Both of these tools will analyze your application, figure out which modules you're using, and assemble a JavaScript file that contains everything you need to load the code in a browser.
You need a base file, a starting point for your application. In our scaffold, we'll call this app.jsx. We'll use Babelify. It's a handy tool that in addition to converting JavaScript to EcmaScript 5 will also to convert React-specific code such as JSX. Browser-sync, which is a tool that auto reloads your code while you edit.
Scaffolding our React app
At the end this will be the final file structure:
Create a folder for the project: reactjs-blueprints
Execute and default all values: npm init
That creates a package.json. Execute npm install --save-dev with all dependencies:
npm install –-save-dev [email protected] [email protected] [email protected] [email protected] [email protected] [email protected]
npm install –-save-dev [email protected] [email protected] [email protected] [email protected] [email protected]
The file package.json will be:
{
"name": "reactjs-blueprints",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"devDependencies": {
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babelify": "^7.2.0",
"browser-sync": "^2.10.0",
"browserify": "^12.0.1",
"browserify-middleware": "^7.0.0",
"express": "^4.13.3",
"react": "^0.14.3",
"react-dom": "^0.14.3",
"reactify": "^1.1.1",
"watchify": "^3.6.1"
}
}
Creates .babelrc file required to run Babel:
{
"presets": ["es2015","react"]
}
Add server.js and declare an Express server used as Node server to run application:
var express = require("express");
var browserify = require('browserify-middleware');
var babelify = require("babelify");
var browserSync = require('browser-sync');
var app = express();
var port = process.env.PORT || 8089;
browserify.settings ({
transform: [babelify.configure({
})],
presets: ["es2015", "react"],
extensions: ['.js', '.jsx'],
grep: /\.jsx?$/
});
// serve client code via browserify
app.get('/bundle.js', browserify(__dirname+'/source/app.jsx'));
// resources
app.get(['*.png','*.jpg','*.css','*.map'], function (req,
res) {
res.sendFile(__dirname+"/public/"+req.path);
});
// all other requests will be routed to index.html
app.get('*', function (req, res) {
res.sendFile(__dirname+"/public/index.html");
});
// Run the server
app.listen(port,function() {
browserSync ({
proxy: 'localhost:' + port,
files: ['source/**/*.{jsx}','public/**/*.{css}'],
options: {
ignored: 'node_modules'
}
});
});
Create folders: source and public. Into source will be .js and .jsx files. Into public will be all css, images files.
Create app.jsx into source folder:
'use strict';
import React from 'react';
import { render } from 'react-dom';
const App = React.createClass({
render() {
return (
<section>
<h1>My scaffold 2</h1>
<p>Hello world 2</p>
</section>
);
}
});
render (
<App />,
document.getElementById('container')
);
Create index.html into public folder:
<!DOCTYPE html>
<html>
<head>
<title>ReactJS Blueprints Modified</title>
<meta charset="utf-8">
<link rel="stylesheet" href="app.css" />
</head>
<body>
<div id="container"></div>
<script src="bundle.js"></script>
</body>
</html>
Also an app.css file into public folder.
body {
background:#eee;
padding:22px;
}
br {
line-height: 2em;
}
h1 {
font-size:24px;
}
h2 {
font-size:18px;
}
To run aplication go to a command line and execute:
node server
This opens a new browser window with the application.