在 react入门系列 里面,介绍了一些react的基础知识,在react基础部分,会结合手脚架工具进行更多的总结。
关于webpack我在这里就不讲解了,有需要的小伙伴可以自己去百度一下学习资料,我这里会贴出来现成的东西供大家使用。
关于es6的内容,在写案例的时候会有涉及,我会贴出来相应的教程,没有了解过es6的小伙伴可以去看一下。
创建项目
1. 创建一个项目文件夹(我是在D盘创建了一个react文件)
2. 进入react文件夹,新建两个文件package.json和webpack.config.js,新建一个src文件夹,如下所示:
下面为了方便大家知道是什么文件夹下的什么文件,我都会以react/xx/xx.xx这样的方式来标明是哪个文件或文件夹,例如上图中的package.json,我就会写成react/package.json
package.json和webpack.config.js内容如下
react/package.json
{
"private": true,
"entry": {},
"dependencies": {
"antd": "^1.1.0",
"atool-build": "0.7.x",
"babel-plugin-antd": "0.4.x",
"babel-plugin-transform-runtime": "^6.8.0",
"babel-runtime": "^6.6.1",
"classnames": "^2.2.3",
"es3ify-loader": "^0.2.0",
"history": "^2.0.1",
"isomorphic-fetch": "^2.2.1",
"js-cookie": "^2.1.1",
"react": "^15.3.2",
"react-dom": "^15.0.2",
"react-redux": "^4.4.5",
"react-router": "^2.0.1",
"spmhandlebars-loader": "^0.1.0"
},
"devDependencies": {
"atool-test-mocha": "^0.1.4",
"babel-eslint": "^6.0.0",
"dora": "0.3.x",
"dora-plugin-browser-history": "^0.1.1",
"dora-plugin-hmr": "0.6.x",
"dora-plugin-livereload": "0.3.x",
"dora-plugin-proxy": "0.6.x",
"dora-plugin-webpack": "0.6.x",
"eslint": "^2.7.0",
"eslint-config-airbnb": "6.x",
"eslint-plugin-react": "4.x",
"expect": "^1.20.1",
"glob": "^7.0.3",
"pre-commit": "1.x",
"react-redux": "^4.4.5",
"redux": "^3.5.2"
},
"pre-commit": [
"lint"
],
"scripts": {
"build": "atool-build",
"lint": "eslint --ext .js,.jsx src",
"start": "dora -p 8001 --plugins \"webpack,hmr,proxy,livereload?enableJs=false&injectHost=127.0.0.1,browser-history?index=/src/entries/index.html\"",
"test": "atool-test-mocha ./src/**/__tests__/*-test.js"
}
}
react/webpack.config.js
// Learn more on how to config.
// - https://github.com/ant-tool/atool-build#配置扩展 const webpack = require('atool-build/lib/webpack');
const fs = require('fs');
const path = require('path');
const glob = require('glob'); module.exports = function(webpackConfig) {
webpackConfig.babel.plugins.push('transform-runtime');
webpackConfig.babel.plugins.push(['antd', {
style: 'css', // if true, use less
}]); // Enable this if you have to support IE8.
// webpackConfig.module.loaders.unshift({
// test: /\.jsx?$/,
// loader: 'es3ify-loader',
// }); // Parse all less files as css module.
webpackConfig.module.loaders.forEach(function(loader, index) {
if (typeof loader.test === 'function' && loader.test.toString().indexOf('\\.less$') > -1) {
loader.test = /\.dont\.exist\.file/;
}
if (loader.test.toString() === '/\\.module\\.less$/') {
loader.test = /\.less$/;
}
}); webpackConfig.module.loaders.push({
test: /\.handlebars$/,
loader: 'spmhandlebars-loader'
}); // Load src/entries/*.js as entry automatically.
const files = glob.sync('./src/entries/*.js');
const newEntries = files.reduce(function(memo, file) {
const name = path.basename(file, '.js');
memo[name] = file;
return memo;
}, {});
webpackConfig.entry = Object.assign({}, webpackConfig.entry, newEntries); return webpackConfig;
};
这里对上面两个文件不做讲解,在下面会对package.json做一些讲解。(关于webpack的一些内容不会讲很多,大家可以去ant-design学习一下,也可以自己去网上找webpack的资料学习。)
3. 进入src文件夹,创建entries文件夹,在entries文件夹里新建index.html、index.css、index.js三个文件
index.html、index.css、index.js三个文件的内容如下(很简单的代码,这里暂时不做讲解,先把项目正常运行了)
react/src/entries/index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Demo</title>
<link rel="stylesheet" href="index.css" />
</head>
<body> <div id="root"></div> <script src="common.js"></script>
<script src="index.js"></script> </body>
</html>
react/src/entries/index.css
html, body, #root {
height: 100%;
}
.box{
background:red;
}
react/src/entries/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css'; function App() {
return (
<div className="box">
demo
</div>
);
} ReactDOM.render(<App />, document.getElementById('root'));
4. 安装依赖
上面的文件都创建好了,返回到react文件夹下,按住shift键,同时点击鼠标右键(如下图所示)
点击“在此处打开命令窗口”,就可以看到如下图所示(注意要在react文件下)
我这里用的是cmd,大家也可以用git进行操作
下一步 :$ npm install,如下图所示
如果装了淘宝镜像,则用 $ cnpm install(淘宝npm镜像--教程)
安装不成功的就多安装几次
安装成功了,在react文件夹下,就可以看到node_modules文件夹
5. 运行/开发调试 项目
在react文件夹下启用cmd(或git),$ npm start,如下图所示
在你的浏览器访问 http://localhost:8989/ 看到下图所示的效果就成功了
6. 构建
$ npm run build,如下图所示
这个时候,你会发现react文件夹里多了一个dist文件夹(里面是压缩后的代码)
现在项目已经创建成功了,下面就进入正题了。
首先要讲的是和 react入门 系列里面不一样的一些写法和注意事项。
JSX
jsx语法和注意事项在 react入门(1) 讲过,这里不再多讲。
组件
在react入门里面,我们也讲了创建组件的写法(react入门1),这里再来介绍几种(包含es6的内容,大家可以去先去了解一下es6)
这里我只对entries文件夹里的index.js里的内容进行修改,其他两个文件不做修改
修改完文件,如果没有看到效果,可以刷新一下http://localhost:8989/ 这个页面,还没有看到效果的,可以重新 $ npm start
案例1:
react/src/entries/index.js(index.html和index.css不变)
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css'; // 方法1
function One() {
return (
<div className="box">demo1</div>
);
} // 方法2
const Two = () => {
return (
<div>demo2</div>
);
}; // 方法3
class Three extends Component{
render(){
return (
<div>demo3</div>
)
}
} // 方法4
const Four=React.createClass({
render:function(){
return (
<div>
<One />
<Two />
<Three />
demo4
</div>
)
}
}); ReactDOM.render(
<Four />,
document.getElementById('root')
)
效果如下
分析一下
下面这张图,结合上面的效果图里用绿色勾出来的部分一起看
将Four组件渲染到id名为root的div里去。这个id名为root的div,在react/src/entries/index.html里可以找到,如下图所示
(react入门1 有讲过具体的原理,这里不再多说)
下面再来看一下引入,都是用import来引入的,如下图所示
前面两个是我们引入下载的的依赖(react/node_modules这个文件夹里可以看到我们下载了哪些依赖,这里不细讲),最后一个是引入css样式。
这里贴一个关于import的教程(原文地址)
下面主要说一下组件的写法,上面我列举了四种写法,我一一来分析
方法1,这种写法我就不多说,相信大家都能看懂
方法2,这个是es6的箭头函数,类似方法1,只是换成了es6的写法。
更加简洁的写法如下
const Two = () => <div>demo2</div>;
贴一个箭头函数的教程帮助大家理解(原文地址)
接下来看一下方法3
方法3,class是es6的内容,如下图所示,可以这么理解
Component是从react里面来的,如下图所示
这里我们的render(){}是直接这么写的,而以前我们都是写的render:function(){},这也是es6的内容。除了render(){}可以写成这样,其他的function都可以这么写,在下面的例子中大家继续看。
贴一个class的教程帮助大家理解(原文地址)
再来看一下方法4
方法4,和我们之前在 react入门 系列里面写的是一样的,这里不再多说。
CSS
在 react入门(1)也介绍了css的写法,这里再来介绍一些不同的写法。
在react/src/entries文件夹里,新建一个文件index.less,如下所示
react/src/entries/index.less内容如下(less教程,这里先不讲less,不懂less的小伙伴就直接在里面写普通的css即可)
.blue{
color:blue
}
.bg{
background:grey
}
案例2:
react/src/entries/index.js(index.html、index.css和index.less不变)
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import styles from './index.less' class App extends Component {
render(){
return(
<div>
<p className='box' style={{color:'#fff'}}>轻音乐</p>
<p className={styles.blue}>摇滚乐</p>
<p className={styles.blue+' '+styles.bg}>抒情音乐</p>
<p className={'box '+styles.blue}>老情歌</p>
</div>
)
}
} ReactDOM.render(
<App />,
document.getElementById('root')
)
效果如下
下面来分析一下
如上图所示,引入了一个css和一个less文件(这里styles可以自定义取名,abc什么的都可以)
下面来看一下css的几种写法
如上图所示,有两种写法
className='box',这个box是在index.css里的,这也是我们之前在 react入门1 里就讲过的写法
style={{color:'#fff'}},这种写法相当于是行内样式,要注意:必须写两个花括号
如上图所示,这个styles是从index.less来的(import styles from './index.less'),这种写法要注意,需要写一个花括号,在blue前要加styles.
如上图所示,当你写多个className时,要注意中间用空格隔开
事件
在 react入门2 里介绍了事件的写法,这里结合es6来介绍几种写法
案例3:
react/src/entries/index.js(index.html、index.css和index.less不变)
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css'; class App extends Component {
clicks(){
alert(1)
}
render(){
return(
<div>
<button onClick={this.clicks.bind(this)}>按钮1</button>
<button onClick={ ()=>alert(2) }>按钮2</button>
</div>
)
}
} ReactDOM.render(
<App />,
document.getElementById('root')
)
效果如下:
分析一下
如上图所示,当点击button的时候,触发onClick事件,然后调用clicks方法。这里要注意的是,格式this.xxx.bind(this)。
如上图所示,在花括号里面写的是 es6的箭头函数(箭头函数在 案例1 贴过教程了)。
props
在子组件通过this.props.xxx来获取父组件传递的信息,在 react入门(2) 讲过,这里不再详细讲解
State
在 react入门3 里面介绍了state,都是在getInitialState里设置初始状态,如下
getInitialState:function(){
return {
val:'red'
};
}
es6的写法又会有所不同,下面来看一个例子
案例4:
react/src/entries/index.js(index.html、index.css和index.less不变)
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css'; class App extends Component {
constructor() {
super();
this.state = {
val:123
};
} render(){
return(
<div>
{this.state.val}
</div>
)
}
} ReactDOM.render(
<App />,
document.getElementById('root')
)
下面来分析:
如上图所示,在设置初始值的时候,是这样写的。
这里说几个注意点:
1. 在constructor(){}里设置state的初始状态。
这里贴一个constructor的教程(原文地址)
2. 初始状态的设置,在 react入门 系列里面,都是在getInitialState里直接return的,而这里要写在this.state{}里
3. super关键字很重要,如果要在constructor里用到this,那么我们必须要写super(),否则会报错。值得一提的是,必须先调用super,才可以使用this,否则也会报错
贴一个关于super的教程(原文地址)
4. 和 react入门 系列里面是一样的,都是通过this.state.xx来获取状态
refs
在 react入门3 里也介绍了的refs的相关知识,这里再总结一下。
案例5:
react/src/entries/index.js(index.html、index.css和index.less不变)
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css'; class Parent extends Component {
constructor() {
super();
this.state = {
val:321
};
} changes(){
this.setState({
val:this.refs.inputs.value
})
} render(){
return(
<div>
<input ref="inputs" value={this.state.val} onChange={this.changes.bind(this)} />
<Child txt={this.state.val} />
</div>
)
}
}
class Child extends Component{
render(){
return(
<span>
{this.props.txt}
</span>
)
}
} ReactDOM.render(
<Parent />,
document.getElementById('root')
)
效果如下
下面来分析一下
- 在constructor里设置val初始值
- input里首先通过this.state.val获取val的值,当input值发生改变的时候,触发onChange事件,调用changes方法。这里ref属性,就相当于给input取了一个名,叫inputs
- 在changes里,通过this.setState重新给val赋值,值为this.refs.inputs.value。this.refs.inputs就相当于获取了ref属性值为inputs的input;this.refs.inputs.value就相当于获取了这个input的value值
- 在子组件Child里,通过this.props.txt获取父组件Parent上Child标签上txt的属性值,即为input的value值
package.json
关于package.json这里讲一下下图列表的东西都是怎么来的吧。
看到上面红色框勾出来的,这里就以react为例来讲解。
"react": "^15.0.2",冒号前面是名字,冒号后面是版本号。
上面列表里的内容都是怎么来的呢?
先将上面红色框勾出来的这一行删除(如下图所示)。
在react文件夹下启动cmd或者git:$ npm install react --save(如下图所示)
完成之后,就可以看到,列表里面又有了react这一行(版本号可能不一样,如下图所示)
当有了上面红框这一行,就表示你成功了,除了这里,还可以在react/node_modules文件夹里也会找到react这个文件夹,如下图所示
有了react/package.json这个文件,你可以把react/node_modules文件夹删除,然后在react文件夹下启动cmd或者git:$ npm i,如下图所示
又会重新安装这些依赖,重新生成node_modules文件夹
关于package.json那些列表里的东西都是做什么的、怎么用,大家可以去npm或者cnpm去查一下
mock数据
在讲解ajax之前,先说一下怎么mock数据吧
在react/src文件夹下新建一个mock文件夹,如下图所示
在react/src/mock文件夹下,新建一个music.json文件,如下图所示
react/src/mock/music.json 文件内容如下
{
"success":true,
"data":[
{
"id":1,
"music":"rock"
},
{
"id":2,
"music":"pop"
},
{
"id":3,
"music":"classical"
}
]
}
在react文件夹下新建proxy.config.js,如下图所示
react/proxy.config.js 内容如下
module.exports = {
'/users': function(req, res) {
res.json({
success: true,
data: [
{
"id":1,
"username":"sam"
},
{
"id":2,
"username":"amy"
},
{
"id":3,
"username":"kim"
}
],
});
}, 'GET /music': './src/mock/music.json'
};
下面来分析
在这里我就写了这两种mock数据的方式,更多的方法戳这里去看:规则定义。
写到这里,我顺带粘贴一下我的文件目录
ajax
关于ajax,我们需要借助别的库、插件、依赖,例如像jquery、zepto、fetch、superagent等等,可以去npm搜索一下ajax挑选自己喜欢的一种。
这里我们用的是isomorphic-fetch(isomorphic-fetch教程),在package.json里可以找到,如下图所示
react/package.json
案例6:
react/src/entries/index.js(index.html、index.css和index.less不变)
import React, { Component, PropTypes } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import fetch from 'isomorphic-fetch'; class Parent extends Component {
componentWillMount(){
var self = this;
fetch('/users')
.then(function(response) {
if (response.status >= 400) {
console.log("Bad response from server");
}
return response.json();
})
.then(function(data) {
self.setState({users:data.data})
});
} constructor() {
super();
this.state = {
users:[]
};
} render(){
return(
<ul>
{
this.state.users.map(function(user, index){
return (
<li key={index}>{user.username}</li>
)
})
}
</ul>
)
}
} ReactDOM.render(
<Parent />,
document.getElementById('root')
)
在react文件夹下启动服务器:$ npm start,在浏览器打开http://localhost:8989/,效果如下
下面来分析一下
componentWillMount,组件即将加载,这时候可以用ajax获取初始化页面需要用到的数据。
下面来分析上面的map循环(在 react入门2 里有讲过map循环),先写一个for循环做对比
var arr = [1,2,3,4];
for(var i=0;i<arr.length;i++){
console.log(arr[i])
}
当然除了isomorphic-fetch,还有其他实现ajax的方法,这里就不讲了。
这次就讲解这么多,有疑问的地方欢迎大家给我留言~~~