在 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的方法,這里就不講了。
這次就講解這么多,有疑問的地方歡迎大家給我留言~~~




