Learning React Series
In this series I wanna discuss my learning experience with ReactJS
, this will be an opinionated series on what I think of ReactJS
& other libraries, Why I switched to it, and why I think ReactJS
is awesome, along side all the opinions I will be sharing code on what I am learning and explaining how it all works.
Note: I have created a github repo that contains all the source code for this article here
Why I bothered learning a new framework
I’ve been a frontend developer for a while now, the last 4 years my work was mostly AngularJS 1.x
& EmberJS
and I think I’m comfortable with both.
For me it all started by checking out AngularJS
and building small apps with it, until the apps I was working on got bigger, I learned about AngularJS
more & knew that the code I wrote was terrible and need a BIG refactoring (I think this happened to most), because AngularJS
is pretty relaxed, there is no restrictions on where to put things, and that was one of the biggest dis-advantages. at least from my perspective
Then life went by and then I started working with a project built with EmberJS
I think it was still in beta, and I had a really difficult time learning it, the concepts were totally different from AngularJS
and I hated it at first.
After that it all clicked, and I LOVED EmberJS
(And still loving it) been working with it exclusively on various projects for the last couple of years.
Until one of my tasks was to make a big app more performant, the problem was that there were too many properties
& observers
so any change triggered list refresh multiple times, dealing with the meta language of ember and the two way bindings was just too much headache, during that time, React
was on fire and I decided to take a look, at first honestly I though its just too difficult, then now even tho I didn’t work on any real/big projects with React
it is my new favourite Library
Note: ember team agrees and they are embracing all the core
React
concepts and they are in the process of integrating them in ember, but this topic is for another article
Setting up the environment
React
doesn’t come with a build tool to init the app, instead you have to do it manually.
React is a low level library and they want to keep it that way, not providing you with a tool like ember-cli
for generating/running/deploying the app is a bit frustrating, but honestly giving you the option to choose whatever you want gives you a lot of possibilities like using cutting edge transpilers for using ES7 with react or honestly anything you could ever think of.
Our module loader/bundler + transpiler will be webpack + babel
Initialize the Application
first install webpack
globally by running
npm install -g webpack
To create a new react application, create a new folder and run the following commands
-
npm init
-
npm install the following list
"dependencies": {
"babel-loader": "^6.2.0",
"babel-plugin-add-module-exports": "^0.1.2",
"babel-plugin-react-html-attrs": "^2.0.0",
"babel-plugin-transform-class-properties": "^6.3.13",
"babel-plugin-transform-decorators-legacy": "^1.3.4",
"babel-preset-es2015": "^6.3.13",
"babel-preset-react": "^6.3.13",
"babel-preset-stage-0": "^6.3.13",
"react": "^0.14.6",
"react-dom": "^0.14.6",
"webpack": "^1.12.9",
"webpack-dev-server": "^1.14.1"
},
let me explain some of the packages introduced in the list above
wepack-dev-server: a tool for running webpack
command in watch mode so whenever any file is changed the compilation happens and fires up a localhost server that serves all the files
react|react-dom after react-native
was introduced, the react team figured out the need for extracting a single library that will be used everywhere and created a web specific library that handles the dom aspect of the web, which is now react-dom
babel presets: presets are bunch of plugins associated together, like es2015
allows the user to write ES6
, react
allows you to write jsx
and stage-0
allows the user to write all cutting edge ES7
stuff
Configure webpack
create a new ./webpack.config.js
that contains the following
var debug = process.env.NODE_ENV !== 'production'
var webpack = require('webpack')
var path = require('path')
module.exports = {
context: path.join(__dirname, 'src'),
devtool: debug ? 'inline-sourcemap' : null,
entry: './js/app.js',
module: {
loaders: [
{
test: /\.js?$/,
exclude: /(node_modules|bower_components)/,
loader: 'babel-loader',
query: {
presets: ['react', 'es2015', 'stage-0'],
plugins: [
'react-html-attrs',
'transform-class-properties',
'transform-decorators-legacy',
],
},
},
],
},
output: {
path: __dirname + '/src/',
filename: 'app.min.js',
},
plugins: debug
? []
: [
new webpack.optimize.DedupePlugin(),
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: false,
sourcemap: false,
}),
],
}
The two interesting properties here are:
-
entry
: which will be our entry point to the app the first script that runs, and through it, loads the rest of the app -
output
: this is the result when running webpack, this will be referenced inindex.html
that we will create bellow
this is a pretty basic webpack config that checks the env, if its production will optimize the code by uglifying it and removing duplicate code and sourcemaps.
There is a concepts in webpack
(actually babel
) which is called loaders through them we can write (ES6, ES7, JSX, …), and it will compile all that to ES5
and will run on all browsers, take a look at the previous link for more info
Note
webpack
is not exclusive for react, its recommended using it or any other build system (Grunt
,Gulp
, ..) for any Javascript application
Note by using
webpack
you will install most of the dependencies fromnpm
notbower
and you can reference it from the code,webpack
will figure how to handle all that for you (and yesnpm
is also a good package manager for the web)
At this point we are done with creating our small build system, its a little effort at first, but it makes our life so much easier, specially when the project grows
####Cool tip on running your app
One of the dependencies for our app is webpack-dev-server
, you could start the app by running
webpack-dev-server
This will actually not work, we need to tell it the base of our app is inside src
, so we would run it with the following instead
webpack-dev-server --content-base src
Instead of doing this every time that we would want to run our app, we could add a command in scripts
in our package.json
"dependencies": {
...
},
"scripts": {
"dev": "./node_modules/.bin/webpack-dev-server --content-base src --inline --hot",
"test": "echo \"Error: no test specified\" && exit 1"
},
We are passing two extra flags
-
--inline
: this will not show a status bar at the top (shows by default) -
--hot
this enables hot module replacement, awesome feature, instead of refreshing the whole page, it just replaces the components that was edited, read more about it here
Now whenever we want to run the app we would type npm run dev
Basic App Structure
our directory structure should look like this
> node_modules/
> src/
> js/
- app.js
> components/
- Hello-World.js
- index.html
- package.json
- webpack.config.js
./index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Learning React Series</title>
</head>
<body>
<div id="app"></div>
<script src="app.min.js"></script>
</body>
</html>
This is just blank html boilerplate, the only interesting part that we are referencing app.min.js
(that we specified in the webpack.config.js
)
./js/app.js
import React from 'react'
import ReactDOM from 'react-dom'
import HelloWorld from './components/Hello-World'
const app = document.getElementById('app')
ReactDOM.render(<HelloWorld />, app)
pretty basic file, just renders the Hello-World
component
./js/components/Hello-World.js
import React from 'react'
export default class HelloWorld extends React.Component {
render() {
let msg = 'Extra Message from React'
return (
<div>
<div>Hello World!</div>
<div>{msg}</div>
</div>
)
}
}
A really simple react
component, just renders
Hello Message
Extra Message from React
That’s it in my next article will be talking about react basics and what is DDAU
(Data down action up), until next time, have an awesome day