Introduction
Web front-end has been exciting these years: new frameworks and tools appear each year. Today, there are three major front-end frameworks: Angular, React, and Vue, and the most popular one is probably React. React stands for the current thinking and trend for front-end development: web components. Also, this is part of the current web development architecture: front-end and back-end separation. For traditional back-end MVC frameworks (like the numerous PHP ones), the View part in these frameworks is not important anymore (do you remember those ‘template engines’?). Back-end becomes Restful APIs or microservices today (the Controllers and Models are still there, and the output is just JSON data fed to front-end and mobile apps).
React
We have been using jQuery for front-end with back-end MVC frameworks for so many years, it is still convenient and great, but in today’s front-end and back-end separation architecture, it is not suitable here anymore. It’s time to switch to React.
React is not just a JavaScript library, it is a whole tech stack (we need to use Babel to transpile ES2015; need to use Webpack to bundle, or pack up, modules; need to use Gulp for automated tasks, etc.). More importantly, React and Redux (and its middleware) stand for a different programming methodology - Functional Programming in front-end applications.
React separates a web page into various components, each component encapsulates:
- Presentation: HTML/JSX
- Style: CSS
- Behavior: JavaScript
And each component can be reusable. All the components together form an app. It sounds very different from what MVC has been promoting for more than a decade: to separate code from HTML. Let’s first create a React component to see what it looks like. If you do not have a React project scaffolding at hand, you can use Facebook’s Create React App tool:
It’s very easy to use, just to run:
npm install --global create-react-ap
to install this npm
package globally. You can also use Yarn (https://yarnpkg.com/en/), another newer NodeJS package manager. Then, you can use this command to create a React project:
create-react-app react-test
and then enter the project directory:
cd react-test/
Now if you take a look at the content of the package.json file:
{
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}
there is a “start
” command in the “scripts
” member. To start the app, run:
npm start
or:
npm run start
(The full command is actually “npm run + xxx
”, but for the start
command, it can be shortened to just “npm start
”). Then in your browser (highly recommend Chrome for React, so far the best), open http://localhost:3000/ to see the app we just created.
You can open the project using your favorite editor or IDE (recommend VS Code for editor or WebStorm/PHPStorm for IDE). The entry file for the project is ./src/index.js.
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
ReactDOM.render(<App />, document.getElementById('root'));
registerServiceWorker();
The page in the browser you just saw is from this component:
import App from './App';
In this component, it also contains its CSS file:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
class App extends Component {
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
</div>
);
}
}
export default App;
So this App component encapsulates CSS, but it has no JavaScript code there, let’s add one button and assign an event handler to it:
import React, { Component } from 'react';
import logo from './logo.svg';
import './App.css';
const buttonStyle = {
margin: '10px',
width: '150px',
backgroundColor: '#F58423',
borderRadius: '3px'
};
class App extends Component {
onButtonClick() {
alert("Clicked the button!");
}
render() {
return (
<div className="App">
<div className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<h2>Welcome to React</h2>
</div>
<p className="App-intro">
To get started, edit <code>src/App.js</code> and save to reload.
</p>
<div>
<button style={buttonStyle} onClick={this.onButtonClick.bind(this)}>Click Me</button>
</div>
</div>
);
}
}
export default App;
Notice the CSS attribute “background-color
” needs to be changed to backgroundColor
in JSX. Why? The reason is all JSX is actually running under JavaScript runtime, they are in fact JavaScript code, and “background-color
” is just not a valid variable name in JavaScript.
Now we need an event handler for the button. In React, we can use onClick
to add an event handler function to an element, but this onClick
is totally different from HTML’s onclick
attribute. Many years ago, developers started to avoid embedding onclick
in HTML, because this will mess up the code. Instead, we have been using jQuery’s way to add event handler function. We would do like this:
<div>
<button id="testButton">Click Me</button>
</div>
in HTML, we have an id
attribute for the button
element, then in <script>
tag, we will use jQuery:
<script src="./jquery.min.js"></script>
<script>
$(document).ready(function () {
$('#testButton').click(function () {
alert("Clicked the button!");
});
});
</script>
jQuery’s way is to:
- Get the button element using CSS rules
- Append an anonymous callback function as the event handler
- In the event callback function, do the things needed for this
onclick
event. For example, to select other DOM elements on the page, and modify/hide/show them
This programming pattern - “when an event occurs, in the callback function, select DOM element to modify or to show/hide it”, is the simplest way and it’s very easy to understand. That’s how jQuery was invented at that time.
Are React and JSX going back? No, React is doing things a different way. When we add the onclick
event handler in HTML, this onclick
event handler function is executed under global scope, which could cause “global variable contamination”. Also adding many event handler functions to the DOM elements could affect page’s performance, especially when there are a great number of them.
But React has no such problems. When we use onClick
in JSX, it is not converted HTML’s onclick
. React uses “event delegation” to handle events, so no matter how many onClick
s we use in JSX, eventually there will just be one event handler function hung on the top of DOM tree. All click events are just captured by this chief event handler function, and then get assigned to a specific function to process.
Also, React has many component life cycle functions, such as:
componentWillMount()
componentDidMount()
shouldComponentUpdate()
componentWillUpdate()
componentDidUpdate()
They are just “hooker functions”. Thanks to these life cycle functions, when a component is unmounted, all the event handler functions for this component will be released. By the way, the naming conversion of these life cycle functions are borrowed from iOS, e.g.:
loadView()
viewDidLoad()
viewWillAppear()
viewDidAppear()
Also React brings with Virtual DOM and its Diff algorithm, because directly manipulating DOM nodes are slowing down page’s performance. Even just one DOM manipulation will cause the browser to layout and render the page again, which is much slower than executing a JavaScript statement. Different from jQuery, React is data-driven: an event triggers data(state) change, then data(state) change triggers render; during rendering, Virtual DOM will compare against last time’s Virtual DOM and spot the differences. Then when to modify the actual DOM tree, it only needs to take care of the changed parts.
From the example above, you can see that traditionally CSS is in .css files, JavaScript is in .js files, and HTML is in .html or template files. React puts these three all in one .js or .jsx file, as the purpose of these three is to work together to implement one functionality. This way shows the discipline of High Cohesion. Today, more and more developers realized back-end’s MVC style might not suit best for front-end, and React (and Redux) brings functional reactive programming into the front-end just in time.
There are some important characters in functional programming:
- Function is the first-class citizen. This is true in JavaScript. One feature many imperative programming languages lack but JavaScript has is to declare one function inside another function. Also, JavaScript function is an object and it can be passed as parameters. Plus, one function's result can also be a function.
- Data is immutable. In “pure” functional programming, data is not changeable, so there are no ‘variables’. All the data cannot be changed, and if it needs to be changed, the only way is to produce new data.
This philosophy is well embodied in React and Redux:
- In React, it emphasis that one component should not change the passed-in props;
- In Redux, one reducer function cannot modify the store’s state, but just generates a new one, often use ES2015’s
Object.assign()
method.
- Use pure function. A pure function is just like a function in math, which has no side effects, meaning the output of the function is only determined by the input.
In React, each component’s render()
function is a pure function. It means the result of the rendering is only determined by the component’s state and props. A formula for React is:
UI = f(state)
In Redux, each reducer must also be a pure function.
Although many projects are still using jQuery, React and Redux brings spring to the front-end area. This transition is not about a new language/library, but a tech stack and a programming paradigm.
P.S. There is a good article called “Thinking in React” by Facebook that is worth reading: