learning's People
learning's Issues
Webpack Learning
webpack learning
Here are some demos to help master Webpack as quickly as possible.
This repo is a collection of simple demos of Webpack.
These demos are purposely written in a simple and clear style. You will find no difficulty in following them to learn the powerful tool.
How to use
First, install Webpack and webpack-dev-server globally.
$ npm i -g webpack webpack-dev-server
Then, clone the repo and install the dependencies.
$ git clone [email protected]:ruanyf/webpack-demos.git
$ cd webpack-demos
$ npm install
Now, play with the source files under the repo's demo* directories.
$ cd demo01
$ webpack-dev-server
Visit http://127.0.0.1:8080 with your browser.
Foreword: What is Webpack
Webpack is a front-end build systems like Grunt and Gulp.
It can be used as a module bundler similar to Browserify, and do much more.
$ browserify main.js > bundle.js
# be equivalent to
$ webpack main.js bundle.js
Its configuration file is webpack.config.js
.
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
After having webpack.config.js
, you can invoke Webpack without any arguments.
$ webpack
Some command-line options you should know.
webpack
– for building once for developmentwebpack -p
– for building once for production (minification)webpack --watch
– for continuous incremental buildwebpack -d
– to include source mapswebpack --colors
– for making things pretty
To produce a production ready application, you could write scripts
field in your package.json file as following.
// package.json
{
// ...
"scripts": {
"dev": "webpack-dev-server --devtool eval --progress --colors",
"deploy": "NODE_ENV=production webpack -p"
},
// ...
}
Index
- Entry file
- Multiple entry files
- Babel-loader
- CSS-loader
- Image loader
- CSS Module
- UglifyJs Plugin
- HTML Webpack Plugin and Open Browser Webpack Plugin
- Environment flags
- Code splitting
- Code splitting with bundle-loader
- Common chunk
- Vendor chunk
- Exposing Global Variables
- Hot Module Replacement
- React router
Demo01: Entry file (source)
Entry file is a file which Webpack will read to build bundle.js.
For example, main.js
is an entry file.
// main.js
document.write('<h1>Hello World</h1>');
index.html
<html>
<body>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
Webpack follows webpack.config.js
to build bundle.js
.
// webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
Launch the server, visit http://127.0.0.1:8080 .
$ webpack-dev-server
Demo02: Multiple entry files (source)
Multiple entry files are allowed. It is useful for a multi-page app.
// main1.js
document.write('<h1>Hello World</h1>');
// main2.js
document.write('<h2>Hello Webpack</h2>');
index.html
<html>
<body>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: {
bundle1: './main1.js',
bundle2: './main2.js'
},
output: {
filename: '[name].js'
}
};
Demo03: Babel-loader (source)
Loaders are preprocessors which transform a resource file of your app (more info). For example, Babel-loader can transform JSX/ES6 file into JS file. Official doc has a complete list of loaders.
main.jsx
is a JSX file.
const React = require('react');
const ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello, world!</h1>,
document.querySelector('#wrapper')
);
index.html
<html>
<body>
<div id="wrapper"></div>
<script src="bundle.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
},
]
}
};
In webpack.config.js
, module.loaders
field is used to assign loaders. The above snippet uses babel-loader
which also needs plugins babel-preset-es2015 and babel-preset-react to transpile ES6 and React. You can also take another way to set the babel query option.
module: {
loaders: [
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['es2015', 'react']
}
}
]
}
Demo04: CSS-loader (source)
Webpack allows you to require CSS in JS file, then preprocessed CSS file with CSS-loader.
main.js
require('./app.css');
app.css
body {
background-color: blue;
}
index.html
<html>
<head>
<script type="text/javascript" src="bundle.js"></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{ test: /\.css$/, loader: 'style-loader!css-loader' },
]
}
};
Attention, you have to use two loaders to transform CSS file. First is CSS-loader to read CSS file, and another is Style-loader to insert Style tag into HTML page. Different loaders are linked by exclamation mark(!).
After launching the server, index.html
will have inline style.
<head>
<script type="text/javascript" src="bundle.js"></script>
<style type="text/css">
body {
background-color: blue;
}
</style>
</head>
Demo05: Image loader (source)
Webpack could also require images in JS files.
main.js
var img1 = document.createElement("img");
img1.src = require("./small.png");
document.body.appendChild(img1);
var img2 = document.createElement("img");
img2.src = require("./big.png");
document.body.appendChild(img2);
index.html
<html>
<body>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{ test: /\.(png|jpg)$/, loader: 'url-loader?limit=8192' }
]
}
};
url-loader transforms image files. If the image size is smaller than 8192 bytes, it will be transformed into Data URL; otherwise, it will be transformed into normal URL. As you see, question mark(?) is be used to pass parameters into loaders.
After launching the server, small.png
and big.png
will have the following URLs.
<img src="data:image/png;base64,iVBOR...uQmCC">
<img src="4853ca667a2b8b8844eb2693ac1b2578.png">
Demo06: CSS Module (source)
css-loader?modules
(the query parameter modules) enables the CSS Modules spec.
It means your module's CSS is local scoped CSS by default. You can switch it off with :global(...)
for selectors and/or rules. (more info)
index.html
<html>
<body>
<h1 class="h1">Hello World</h1>
<h2 class="h2">Hello Webpack</h2>
<div id="example"></div>
<script src="./bundle.js"></script>
</body>
</html>
app.css
.h1 {
color:red;
}
:global(.h2) {
color: blue;
}
main.jsx
var React = require('react');
var ReactDOM = require('react-dom');
var style = require('./app.css');
ReactDOM.render(
<div>
<h1 className={style.h1}>Hello World</h1>
<h2 className="h2">Hello Webpack</h2>
</div>,
document.getElementById('example')
);
webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
{
test: /\.css$/,
loader: 'style-loader!css-loader?modules'
}
]
}
};
Launch the server.
$ webpack-dev-server
Visit http://127.0.0.1:8080 , you'll find that only second h1
is red, because its CSS is local scoped, and both h2
is blue, because its CSS is global scoped.
Demo07: UglifyJs Plugin (source)
Webpack has a plugin system to expand its functions. For example, UglifyJs Plugin will minify output(bundle.js
) JS codes.
main.js
var longVariableName = 'Hello';
longVariableName += ' World';
document.write('<h1>' + longVariableName + '</h1>');
index.html
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require('webpack');
var uglifyJsPlugin = webpack.optimize.UglifyJsPlugin;
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new uglifyJsPlugin({
compress: {
warnings: false
}
})
]
};
After launching the server, main.js
will be minified into following.
var o="Hello";o+=" World",document.write("<h1>"+o+"</h1>")
Demo08: HTML Webpack Plugin and Open Browser Webpack Plugin (source)
This demo shows you how to load 3rd-party plugins.
html-webpack-plugin could create index.html
for you, and open-browser-webpack-plugin could open a new browser tab when Webpack loads.
main.js
document.write('<h1>Hello World</h1>');
webpack.config.js
var HtmlwebpackPlugin = require('html-webpack-plugin');
var OpenBrowserPlugin = require('open-browser-webpack-plugin');
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [
new HtmlwebpackPlugin({
title: 'Webpack-demos'
}),
new OpenBrowserPlugin({
url: 'http://localhost:8080'
})
]
};
Run webpack-dev-server
.
$ webpack-dev-server
Now you don't need to write index.html
by hand and don't have to open browser by yourself. Webpack did all these things for you.
Demo09: Environment flags (source)
You can enable some codes only in development environment with environment flags.
main.js
document.write('<h1>Hello World</h1>');
if (__DEV__) {
document.write(new Date());
}
index.html
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require('webpack');
var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'false'))
});
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
},
plugins: [devFlagPlugin]
};
Now pass environment variable into webpack.
# Linux & Mac
$ env DEBUG=true webpack-dev-server
# Windows
$ DEBUG=true webpack-dev-server
Demo10: Code splitting (source)
For big web apps it’s not efficient to put all code into a single file, Webpack allows you to split them into several chunks. Especially if some blocks of code are only required under some circumstances, these chunks could be loaded on demand.
At first, you use require.ensure
to define a split point. (official document)
// main.js
require.ensure(['./a'], function(require) {
var content = require('./a');
document.open();
document.write('<h1>' + content + '</h1>');
document.close();
});
require.ensure
tells Webpack that ./a.js
should be separated from bundle.js
and built into a single chunk file.
// a.js
module.exports = 'Hello World';
Now Webpack takes care of the dependencies, output files and runtime stuff. You don't have to put any redundancy into your index.html
and webpack.config.js
.
<html>
<body>
<script src="bundle.js"></script>
</body>
</html>
webpack.config.js
module.exports = {
entry: './main.js',
output: {
filename: 'bundle.js'
}
};
Launch the server.
$ webpack-dev-server
On the surface, you won't feel any differences. However, Webpack actually builds main.js
and a.js
into different chunks(bundle.js
and 1.bundle.js
), and loads 1.bundle.js
from bundle.js
when on demand.
Demo11: Code splitting with bundle-loader (source)
Another way of code splitting is using bundle-loader.
// main.js
// Now a.js is requested, it will be bundled into another file
var load = require('bundle-loader!./a.js');
// To wait until a.js is available (and get the exports)
// you need to async wait for it.
load(function(file) {
document.open();
document.write('<h1>' + file + '</h1>');
document.close();
});
require('bundle-loader!./a.js')
tells Webpack to load a.js
from another chunk.
Now Webpack will build main.js
into bundle.js
, and a.js
into 1.bundle.js
.
Demo12: Common chunk (source)
When multi scripts have common chunks, you can extract the common part into a separate file with CommonsChunkPlugin.
// main1.jsx
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>Hello World</h1>,
document.getElementById('a')
);
// main2.jsx
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h2>Hello Webpack</h2>,
document.getElementById('b')
);
index.html
<html>
<body>
<div id="a"></div>
<div id="b"></div>
<script src="init.js"></script>
<script src="bundle1.js"></script>
<script src="bundle2.js"></script>
</body>
</html>
webpack.config.js
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin");
module.exports = {
entry: {
bundle1: './main1.jsx',
bundle2: './main2.jsx'
},
output: {
filename: '[name].js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
]
},
plugins: [
new CommonsChunkPlugin('init.js')
]
}
Demo13: Vendor chunk (source)
You can also extract the vendor libraries from a script into a separate file with CommonsChunkPlugin.
main.js
var $ = require('jquery');
$('h1').text('Hello World');
index.html
<html>
<body>
<h1></h1>
<script src="vendor.js"></script>
<script src="bundle.js"></script>
</body>
</html>
webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js',
vendor: ['jquery'],
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.optimize.CommonsChunkPlugin(/* chunkName= */'vendor', /* filename= */'vendor.js')
]
};
If you want a module available as variable in every module, such as making $ and jQuery available in every module without writing require("jquery")
. You should use ProvidePlugin
(Official doc).
// main.js
$('h1').text('Hello World');
// webpack.config.js
var webpack = require('webpack');
module.exports = {
entry: {
app: './main.js'
},
output: {
filename: 'bundle.js'
},
plugins: [
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery"
})
]
};
Demo14: Exposing global variables (source)
If you want to use some global variables, and don't want to include them in the Webpack bundle, you can enable externals
field in webpack.config.js
(official document).
For example, we have a data.js
.
var data = 'Hello World';
We can expose data
as a global variable.
// webpack.config.js
module.exports = {
entry: './main.jsx',
output: {
filename: 'bundle.js'
},
module: {
loaders:[
{
test: /\.js[x]?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['es2015', 'react']
}
},
]
},
externals: {
// require('data') is external and available
// on the global var data
'data': 'data'
}
};
Now, you require data
as a module variable in your script. but it actually is a global variable.
// main.jsx
var data = require('data');
var React = require('react');
var ReactDOM = require('react-dom');
ReactDOM.render(
<h1>{data}</h1>,
document.body
);
Demo15: Hot Module Replacement (source)
Hot Module Replacement (HMR) exchanges, adds, or removes modules while an application is running without a page reload.
You have two ways to enable Hot Module Replacement with the webpack-dev-server.
(1) Specify --hot
and --inline
on the command line
$ webpack-dev-server --hot --inline
Meaning of the options:
--hot
: adds the HotModuleReplacementPlugin and switch the server to hot mode.--inline
: embed the webpack-dev-server runtime into the bundle.--hot --inline
: also adds the webpack/hot/dev-server entry.
(2) Modify webpack.config.js
.
- add
new webpack.HotModuleReplacementPlugin()
to theplugins
field - add
webpack/hot/dev-server
andwebpack-dev-server/client?http://localhost:8080
to theentry
field
webpack.config.js
looks like the following.
var webpack = require('webpack');
var path = require('path');
module.exports = {
entry: [
'webpack/hot/dev-server',
'webpack-dev-server/client?http://localhost:8080',
'./index.js'
],
output: {
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin()
],
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['babel-loader'],
query: {
presets: ['es2015', 'react']
},
include: path.join(__dirname, '.')
}]
}
};
Now launch the dev server.
$ webpack-dev-server
Visiting http://localhost:8080, you should see 'Hello World' in your browser.
Don't close the server. Open a new terminal to edit App.js
, and modify 'Hello World' into 'Hello Webpack'. Save it, and see what happened in the browser.
App.js
import React, { Component } from 'react';
export default class App extends Component {
render() {
return (
<h1>Hello World</h1>
);
}
}
index.js
import React from 'react';
import ReactDOM = require('react-dom');
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
index.html
<html>
<body>
<div id='root'></div>
<script src="/static/bundle.js"></script>
</body>
</html>
Demo16: React router (source)
This demo uses webpack to build React-router's official example.
Let's imagine a little app with a dashboard, inbox, and calendar.
+---------------------------------------------------------+
| +---------+ +-------+ +--------+ |
| |Dashboard| | Inbox | |Calendar| Logged in as Jane |
| +---------+ +-------+ +--------+ |
+---------------------------------------------------------+
| |
| Dashboard |
| |
| |
| +---------------------+ +----------------------+ |
| | | | | |
| | + + | +---------> | |
| | | | | | | |
| | | + | | +-------------> | |
| | | | + | | | | |
| | | | | | | | | |
| +-+---+----+-----+----+ +----------------------+ |
| |
+---------------------------------------------------------+
$ webpack-dev-server --history-api-fallback
Useful links
- Webpack docs
- webpack-howto, by Pete Hunt
- Diving into Webpack, by Web Design Weekly
- Webpack and React is awesome, by Christian Alfoni
- Browserify vs Webpack, by Cory House
- React Webpack cookbook, by Christian Alfoni
License
MIT
React learning
React learning
here are some demos to help you learn React as quickly as possible.
This is a collection of simple demos of React.js.
These demos are purposely written in a simple and clear style. You will find no difficulty in following them to learn the powerful library.
Related Projects
- Flux Demo
- Webpack Demos
- React Router Tutorial
- React Testing Demo
- A boilerplate for React-Babel-Webpack project
How to use
First copy the repo into your disk.
$ git clone [email protected]:ruanyf/react-demos.git
Then play with the source files under the repo's demo* directories.
HTML Template
<!DOCTYPE html>
<html>
<head>
<script src="../build/react.js"></script>
<script src="../build/react-dom.js"></script>
<script src="../build/browser.min.js"></script>
</head>
<body>
<div id="example"></div>
<script type="text/babel">
// ** Our code goes here! **
</script>
</body>
</html>
Index
- Render JSX
- Use JavaScript in JSX
- Use array in JSX
- Define a component
- this.props.children
- PropTypes
- Finding a DOM node
- this.state
- Form
- Component Lifecycle
- Ajax
- Display value from a Promise
- Server-side rendering
Demo01: Render JSX
The template syntax in React is called JSX. It is allowed in JSX to put HTML tags directly into JavaScript codes. ReactDOM.render()
is the method which translates JSX into HTML, and renders it into the specified DOM node.
ReactDOM.render(
<h1>Hello, world!</h1>,
document.getElementById('example')
);
Attention, you have to use <script type="text/babel">
to indicate JSX codes, and include browser.min.js
, which is a browser version of Babel and could be get inside a babel-core npm release, to actually perform the transformation in the browser.
Before v0.14, React use JSTransform.js
to translate <script type="text/jsx">
. It has been deprecated (more info).
Demo02: Use JavaScript in JSX
You could also use JavaScript in JSX. It takes angle brackets (<) as the beginning of HTML syntax, and curly brackets ({) as the beginning of JavaScript syntax.
var names = ['Alice', 'Emily', 'Kate'];
ReactDOM.render(
<div>
{
names.map(function (name) {
return <div>Hello, {name}!</div>
})
}
</div>,
document.getElementById('example')
);
Demo03: Use array in JSX
If a JavaScript variable is an array, JSX will implicitly concat all members of the array.
var arr = [
<h1>Hello world!</h1>,
<h2>React is awesome</h2>,
];
ReactDOM.render(
<div>{arr}</div>,
document.getElementById('example')
);
Demo04: Define a component
React.createClass()
creates a component class, which implements a render method to return an component instance of the class. You don't need to call new
on the class in order to get an instance, just use it as a normal HTML tag.
var HelloMessage = React.createClass({
render: function() {
return <h1>Hello {this.props.name}</h1>;
}
});
ReactDOM.render(
<HelloMessage name="John" />,
document.getElementById('example')
);
Components would have attributes, and you can use this.props.[attribute]
to access them, just like this.props.name
of <HelloMessage name="John" />
is John.
Please remember the first letter of the component's name must be capitalized, otherwise React will throw an error. For instance, HelloMessage
as a component's name is OK, but helloMessage
is not allowed. And a React component should only have one top child node.
// wrong
var HelloMessage = React.createClass({
render: function() {
return <h1>
Hello {this.props.name}
</h1><p>
some text
</p>;
}
});
// correct
var HelloMessage = React.createClass({
render: function() {
return <div>
<h1>Hello {this.props.name}</h1>
<p>some text</p>
</div>;
}
});
Demo05: this.props.children
React uses this.props.children
to access a component's children nodes.
var NotesList = React.createClass({
render: function() {
return (
<ol>
{
React.Children.map(this.props.children, function (child) {
return <li>{child}</li>;
})
}
</ol>
);
}
});
ReactDOM.render(
<NotesList>
<span>hello</span>
<span>world</span>
</NotesList>,
document.body
);
Please be mindful that the value of this.props.children
has three possibilities. If the component has no children node, the value is undefined
; If single children node, an object; If multiple children nodes, an array. You should be careful to handle it.
React gave us an utility React.Children
for dealing with the this.props.children
's opaque data structure. You could use React.Children.map
to iterate this.props.children
without worring its data type being undefined
or object
. Check official document for more methods React.Children
offers.
Demo06: PropTypes
Components have many specific attributes which are called ”props” in React and can be of any type.
Sometimes you need a way to validate these props. You don't want users have the freedom to input anything into your components.
React has a solution for this and it's called PropTypes.
var MyTitle = React.createClass({
propTypes: {
title: React.PropTypes.string.isRequired,
},
render: function() {
return <h1> {this.props.title} </h1>;
}
});
The above component of MyTitle
has a props of title
. PropTypes tells React that the title is required and its value should be a string.
Now we give Title
a number value.
var data = 123;
ReactDOM.render(
<MyTitle title={data} />,
document.body
);
It means the props doesn't pass the validation, and the console will show you an error message.
Warning: Failed propType: Invalid prop `title` of type `number` supplied to `MyTitle`, expected `string`.
Visit official doc for more PropTypes options.
P.S. If you want to give the props a default value, use getDefaultProps()
.
var MyTitle = React.createClass({
getDefaultProps : function () {
return {
title : 'Hello World'
};
},
render: function() {
return <h1> {this.props.title} </h1>;
}
});
ReactDOM.render(
<MyTitle />,
document.body
);
Demo07: Finding a DOM node
Sometimes you need to reference a DOM node in a component. React gives you the ref
attribute to find it.
var MyComponent = React.createClass({
handleClick: function() {
this.refs.myTextInput.focus();
},
render: function() {
return (
<div>
<input type="text" ref="myTextInput" />
<input type="button" value="Focus the text input" onClick={this.handleClick} />
</div>
);
}
});
ReactDOM.render(
<MyComponent />,
document.getElementById('example')
);
The desired DOM node should have a ref
attribute, and this.refs.[refName]
would return the corresponding DOM node. Please be mindful that you could do that only after this component has been mounted into the DOM, otherwise you get null
.
Demo08: this.state
React thinks of component as state machines, and uses this.state
to hold component's state, getInitialState()
to initialize this.state
(invoked before a component is mounted), this.setState()
to update this.state
and re-render the component.
var LikeButton = React.createClass({
getInitialState: function() {
return {liked: false};
},
handleClick: function(event) {
this.setState({liked: !this.state.liked});
},
render: function() {
var text = this.state.liked ? 'like' : 'haven\'t liked';
return (
<p onClick={this.handleClick}>
You {text} this. Click to toggle.
</p>
);
}
});
ReactDOM.render(
<LikeButton />,
document.getElementById('example')
);
You could use component attributes to register event handlers, just like onClick
, onKeyDown
, onCopy
, etc. Official Document has all supported events.
Demo09: Form
According to React's design philosophy, this.state
describes the state of component and is mutated via user interactions, and this.props
describes the properties of component and is stable and immutable.
Since that, the value
attribute of Form components, such as <input>, <textarea>, and <option>, is unaffected by any user input. If you wanted to access or update the value in response to user input, you could use the onChange event.
var Input = React.createClass({
getInitialState: function() {
return {value: 'Hello!'};
},
handleChange: function(event) {
this.setState({value: event.target.value});
},
render: function () {
var value = this.state.value;
return (
<div>
<input type="text" value={value} onChange={this.handleChange} />
<p>{value}</p>
</div>
);
}
});
ReactDOM.render(<Input/>, document.body);
More information on official document.
Demo10: Component Lifecycle
Components have three main parts of their lifecycle: Mounting(being inserted into the DOM), Updating(being re-rendered) and Unmounting(being removed from the DOM). React provides hooks into these lifecycle part. will
methods are called right before something happens, and did
methods which are called right after something happens.
var Hello = React.createClass({
getInitialState: function () {
return {
opacity: 1.0
};
},
componentDidMount: function () {
this.timer = setInterval(function () {
var opacity = this.state.opacity;
opacity -= .05;
if (opacity < 0.1) {
opacity = 1.0;
}
this.setState({
opacity: opacity
});
}.bind(this), 100);
},
render: function () {
return (
<div style={{opacity: this.state.opacity}}>
Hello {this.props.name}
</div>
);
}
});
ReactDOM.render(
<Hello name="world"/>,
document.body
);
The following is a whole list of lifecycle methods.
- componentWillMount(): Fired once, before initial rendering occurs. Good place to wire-up message listeners.
this.setState
doesn't work here. - componentDidMount(): Fired once, after initial rendering occurs. Can use
this.getDOMNode()
. - componentWillUpdate(object nextProps, object nextState): Fired after the component's updates are made to the DOM. Can use
this.getDOMNode()
for updates. - componentDidUpdate(object prevProps, object prevState): Invoked immediately after the component's updates are flushed to the DOM. This method is not called for the initial render. Use this as an opportunity to operate on the DOM when the component has been updated.
- componentWillUnmount(): Fired immediately before a component is unmounted from the DOM. Good place to remove message listeners or general clean up.
- componentWillReceiveProps(object nextProps): Fired when a component is receiving new props. You might want to
this.setState
depending on the props. - shouldComponentUpdate(object nextProps, object nextState): Fired before rendering when new props or state are received.
return false
if you know an update isn't needed.
Demo11: Ajax
How to get the data of a component from a server or an API provider? The answer is using Ajax to fetch data in the event handler of componentDidMount
. When the server response arrives, store the data with this.setState()
to trigger a re-render of your UI.
var UserGist = React.createClass({
getInitialState: function() {
return {
username: '',
lastGistUrl: ''
};
},
componentDidMount: function() {
$.get(this.props.source, function(result) {
var lastGist = result[0];
if (this.isMounted()) {
this.setState({
username: lastGist.owner.login,
lastGistUrl: lastGist.html_url
});
}
}.bind(this));
},
render: function() {
return (
<div>
{this.state.username}'s last gist is
<a href={this.state.lastGistUrl}>here</a>.
</div>
);
}
});
ReactDOM.render(
<UserGist source="https://api.github.com/users/octocat/gists" />,
document.body
);
Demo12: Display value from a Promise
This demo is inspired by Nat Pryce's article "Higher Order React Components".
If a React component's data is received asynchronously, we can use a Promise object as the component's property also, just as the following.
ReactDOM.render(
<RepoList
promise={$.getJSON('https://api.github.com/search/repositories?q=javascript&sort=stars')}
/>,
document.body
);
The above code takes data from Github's API, and the RepoList
component gets a Promise object as its property.
Now, while the promise is pending, the component displays a loading indicator. When the promise is resolved successfully, the component displays a list of repository information. If the promise is rejected, the component displays an error message.
var RepoList = React.createClass({
getInitialState: function() {
return { loading: true, error: null, data: null};
},
componentDidMount() {
this.props.promise.then(
value => this.setState({loading: false, data: value}),
error => this.setState({loading: false, error: error}));
},
render: function() {
if (this.state.loading) {
return <span>Loading...</span>;
}
else if (this.state.error !== null) {
return <span>Error: {this.state.error.message}</span>;
}
else {
var repos = this.state.data.items;
var repoList = repos.map(function (repo) {
return (
<li>
<a href={repo.html_url}>{repo.name}</a> ({repo.stargazers_count} stars) <br/> {repo.description}
</li>
);
});
return (
<main>
<h1>Most Popular JavaScript Projects in Github</h1>
<ol>{repoList}</ol>
</main>
);
}
}
});
Demo13: Server-side rendering
This demo is copied from github.com/mhart/react-server-example, but I rewrote it with JSX syntax.
# install the dependencies in demo13 directory
$ npm install
# translate all jsx file in src subdirectory to js file
$ npm run build
# launch http server
$ node server.js
Extras
Precompiling JSX
All above demos don't use JSX compilation for clarity. In production environment, ensure to precompile JSX files before putting them online.
First, install the command-line tools Babel.
$ npm install -g babel
Then precompile your JSX files(.jsx) into JavaScript(.js). Compiling the entire src directory and output it to the build directory, you may use the option --out-dir
or -d
.
$ babel src --out-dir build
Put the compiled JS files into HTML.
<!DOCTYPE html>
<html>
<head>
<title>Hello React!</title>
<script src="build/react.js"></script>
<script src="build/react-dom.js"></script>
<!-- No need for Browser.js! -->
</head>
<body>
<div id="example"></div>
<script src="build/helloworld.js"></script>
</body>
</html>
Useful links
- React's official site
- React's official examples
- React (Virtual) DOM Terminology, by Sebastian Markbåge
- The React Quick Start Guide, by Jack Callister
- Learning React.js: Getting Started and Concepts, by Ken Wheeler
- Getting started with React, by Ryan Clark
- React JS Tutorial and Guide to the Gotchas, by Justin Deal
- React Primer, by Binary Muse
- jQuery versus React.js thinking, by zigomir
License
BSD licensed
利用javascri去代替库
尽管jQuery帮助开发者节省了大量的工作,但是并不是所有的产品都适合使用jQuery。jQuery 2.0.3版本有236KB,压缩版也有81KB,这意味着你的Web产品需要额外的加载时间和带宽,而在移动设备上则需要更多。
如果你的产品中只有少量的前端效果或DOM操作,那么完全可以抛弃臃肿的jQuery,转而使用JavaScript原生API来实现。
以下是jQuery和JavaScript实现相同操作的等价代码。
选择元素
- // jQuery
- var els = $('.el');
- // 原生方法
- var els = document.querySelectorAll('.el');
- // 函数法
- var $ = function (el) {
- return document.querySelectorAll(el);
- }
- var els = $('.el');
- // 或者使用regex-based micro-selector库,地址:http://jsperf.com/micro-selector-libraries
// jQuery var els = $('.el');// 原生方法
var els = document.querySelectorAll('.el');// 函数法
var $ = function (el) {
return document.querySelectorAll(el);
}var els = $('.el');
// 或者使用regex-based micro-selector库,地址:http://jsperf.com/micro-selector-libraries
创建元素
- // jQuery
- var newEl = $('<div/>');
- // 原生方法
- var newEl = document.createElement('div');
// jQuery
var newEl = $('<div/>');// 原生方法
var newEl = document.createElement('div');
添加事件监听器
- // jQuery
- $('.el').on('event', function() {
- });
- // 原生方法
- [].forEach.call(document.querySelectorAll('.el'), function (el) {
- el.addEventListener('event', function() {
- }, false);
- });
// jQuery
$('.el').on('event', function() {});
// 原生方法
[].forEach.call(document.querySelectorAll('.el'), function (el) {
el.addEventListener('event', function() {}, false);
});
设置/获取属性
- // jQuery
- $('.el').filter(':first').attr('key', 'value');
- $('.el').filter(':first').attr('key');
- // 原生方法
- document.querySelector('.el').setAttribute('key', 'value');
- document.querySelector('.el').getAttribute('key');
// jQuery
$('.el').filter(':first').attr('key', 'value');
$('.el').filter(':first').attr('key');// 原生方法
document.querySelector('.el').setAttribute('key', 'value');
document.querySelector('.el').getAttribute('key');
添加/移除/切换类
- // jQuery
- $('.el').addClass('class');
- $('.el').removeClass('class');
- $('.el').toggleClass('class');
- // 原生方法
- document.querySelector('.el').classList.add('class');
- document.querySelector('.el').classList.remove('class');
- document.querySelector('.el').classList.toggle('class');
// jQuery
$('.el').addClass('class');
$('.el').removeClass('class');
$('.el').toggleClass('class');// 原生方法
document.querySelector('.el').classList.add('class');
document.querySelector('.el').classList.remove('class');
document.querySelector('.el').classList.toggle('class');
附加内容(Append)
- // jQuery
- $('.el').append($('<div/>'));
- // 原生方法
- document.querySelector('.el').appendChild(document.createElement('div'));
// jQuery
$('.el').append($('<div/>'));// 原生方法
document.querySelector('.el').appendChild(document.createElement('div'));
克隆元素
- // jQuery
- var clonedEl = $('.el').clone();
- // 原生方法
- var clonedEl = document.querySelector('.el').cloneNode(true);
// jQuery
var clonedEl = $('.el').clone();// 原生方法
var clonedEl = document.querySelector('.el').cloneNode(true);
移除元素
- // jQuery
- $('.el').remove();
- // 原生方法
- remove('.el');
- function remove(el) {
- var toRemove = document.querySelector(el);
- toRemove.parentNode.removeChild(toRemove);
- }
// jQuery
$('.el').remove();// 原生方法
remove('.el');function remove(el) {
var toRemove = document.querySelector(el);toRemove.parentNode.removeChild(toRemove);
}
获取父元素
- // jQuery
- $('.el').parent();
- // 原生方法
- document.querySelector('.el').parentNode;
// jQuery
$('.el').parent();// 原生方法
document.querySelector('.el').parentNode;
上一个/下一个元素
- // jQuery
- $('.el').prev();
- $('.el').next();
- // 原生方法
- document.querySelector('.el').previousElementSibling;
- document.querySelector('.el').nextElementSibling;
// jQuery
$('.el').prev();
$('.el').next();// 原生方法
document.querySelector('.el').previousElementSibling;
document.querySelector('.el').nextElementSibling;
XHR或AJAX
- // jQuery
- $.get('url', function (data) {
- });
- $.post('url', {data: data}, function (data) {
- });
- // 原生方法
- // get
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url);
- xhr.onreadystatechange = function (data) {
- }
- xhr.send();
- // post
- var xhr = new XMLHttpRequest()
- xhr.open('POST', url);
- xhr.onreadystatechange = function (data) {
- }
- xhr.send({data: data});
// jQuery
$.get('url', function (data) {});
$.post('url', {data: data}, function (data) {});
// 原生方法
// get
var xhr = new XMLHttpRequest();xhr.open('GET', url);
xhr.onreadystatechange = function (data) {}
xhr.send();// post
var xhr = new XMLHttpRequest()xhr.open('POST', url);
xhr.onreadystatechange = function (data) {}
xhr.send({data: data});
以上这些只是很少一部分,你可以在浏览器的控制台中找到更多东西,或者可以参考MDN的JS API reference或者WPD的DOM文档。
你也可以使用其他非常轻量级的库代替,比如http://microjs.com/列出的一些库,根据你的需求选择最合适的库,但首先要清楚,除非是不使用库无法实现某项功能,否则还是使用原生JavaScript。
英文原文:How to forget about jQuery and start using native JavaScript APIs
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.