本節包含內容有
React背景及特點
創建React應用
開始第一個簡單程序 - 運行Hello World
JSX語法入門
組件
Props
state
組件的生命周期
React背景及特點
-
React背景介紹
在Web應用開發的早期,構建Web應用的唯一方式就是向服務器發送請求,然后服務器響應請求并返回一個完整的頁面。從開發角度上講這種方式非常簡單,但是這種開發方式會造成很不好的用戶體驗,用戶的很多行為都需要向服務器請求,等待服務器的反應。因此,開發者開始開發各種類庫,使用JavaScript在瀏覽器端渲染應用。
React起源于Facebook公司,期初用于Instagram網站開發。React是一個用于構建用戶界面的JavaScript庫,不是一個MVC框架,提出了一種新的開發模式和理念,它強調的是“用戶界面”。
-
React特點
1.作為UI
React可以作為MVC中的View層進行使用,并且在已有項目中很容易使用React開發新功能。
2.虛擬DOM虛擬DOM是React最重要的特性,實現了優化視圖的渲染和刷新。以前沒有Ajax技術的時候,Web頁面從服務器端整體渲染出HTML,輸出到瀏覽器端進行渲染,同樣的,用戶的一個改變頁面的操作也會刷新整個頁面來完成。知道Ajax的出現,實現頁面局部刷新,帶來的高效和分離讓Web開發者們驚嘆不已。但隨之而來的問題是復雜的用戶交互及展現需要通過大量的DOM操作來完成,這讓頁面的性能以及開發的效率又出現了新的瓶頸。如何進行高性能的復雜DOM操作通常是衡量一個前端開發人員技能的重要指標。
時至今日,談到前端性能優化,減少DOM元素,減少reflow和repaint,編碼過程盡量減少DOM的查詢等手段是大家耳熟能詳的。而頁面任何UI的變化都是通過整體刷新來完成的。而React之所以快,是因為它不直接操作DOM,而是引進虛擬DOM的實現來解決這個問題。
3.組件化
虛擬DOM(virtual-dom)不僅帶來了簡單UI開發邏輯,同時也帶來了組件化開發的思想。所謂組件,即封裝起來的具有獨立功能的UI部件。React推薦以組件的方式去重新思考UI構成,將UI上每一個功能相對獨立的模塊定義出呢個組件,然后將小的組件通過組合或者嵌套的方式構成的大的組件,最終完成整體UI的構建。
如果說MVC的思想讓你做到視圖-數據-控制器的分離。那么組件化的思考方式則是帶來了UI功能模塊之間的分離。
對于React而言,開發者從功能的角度出發,將UI分成不同的組件,每個組件都獨立封裝。在React中,你按照界面模塊自然劃分的方式來組織和編寫你的代碼。每個組件只關心自己部分的邏輯,彼此獨立。React組件應該具有如下特征:可組合、可重用、可維護
4.數據流
React實現了單向的數據流,相對于傳統的數據綁定,React更加靈活、便捷。
-
React學習準備
1、前端基礎知識:HTML,CSS,JavaScript
2、JSX語法
3、ES6相關知識
4、React中文網站:http://www.css88.com/react/index.html -
React和ReactNative的關系
React用于Web用用開發。ReactNative采用React方式進行移動應用開發。
ReactNative采用React語法,用于進行JavaScript跨終端應用開發,既擁有原生Native的交互體驗,又能夠保留React自由的開發效率。使用靈活的HTML和CSS布局,使用React語法構建組件,然后同時運行在iOS和Android平臺上,“Learn once,write anywhere”
1.創建React應用
使用命令行:
npm install -g create-react-app
create-react-app my-app
在my-app目錄下運行npm
cd my-app
npm start
這時候在瀏覽器中就會顯示運行結果,可以在index.js文件下進行修改
整個文件目錄是2.運行Hello World
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import './index.css';
// React的最基本方法,用于將模板轉換成HTML語言,渲染DOM并插入指定的DOM節點
/*
三個參數
第一個:模板的渲染內容(HTML形式)
第二個: 這段模板需要插入的DOM節點,本程序中id為root的div節點
第三個:渲染后的回調,一般不用
*/
ReactDOM.render(
<h1>Hello World</h1>
document.getElementById('root')
);
registerServiceWorker();
3.JSX入門
JSX不是一門新的語言,是個語法(語法糖)
- JSX必須借助React環境運行
- JSX標簽其實就是HTML標簽,只不過我們在JavaScript中書寫這些標簽的時候,不用使用“”括起來
<h1>Hello World</h1> 這就是JSX語法
- 轉換:JSX語法能夠讓我們更直觀的看到組件的DOM結構,不能直接在瀏覽器上運行,最終會轉化成JavaScript代碼
// JSX語法書寫
ReactDOM.render(
<h1>
Hello React
</h1>,
document.getElementById('root')
);
// JavaScript語法書寫
ReactDOM.render(
React.createElement("h1", null, "Hello React"),
document.getElementById('root')
);
兩種寫法的比較,可以看出來JSX的寫法結構很清晰,書寫也簡單。
- 如何在JSX中運行JavaScript代碼,使用{表達式}括起來,如下邊的寫法
var text = "世界"
ReactDOM.render(
<h1>{text}</h1>,
document.getElementById('root')
);
- JSX語法在屬性、設置樣式和事件綁定等中的應用
4.組件
(1)定義組件
創建一個組件類,用于輸出Hello React
var HelloMessage = React.createClass({
render: function () {
// return <h1>Hello React</h1>;
// 如果想動態輸出內容這里使用屬性
return <h1>{this.props.helloText}</h1>
}
});
ReactDOM.render(
// 在模板中插入<HelloMessage />會自動生成一個實例
<HelloMessage helloText="Hello React"/>,
document.getElementById('root')
);
- React中創建的組件類以大寫字母開頭,駝峰命名法
- 在React中使用React.creatClass方法創建一個組件類
- 核心代碼:每個組件都必須實現自己的render方法。輸出定義好的組件模板。返回值:null,false,組件模板
- 注意:組件類只能包含一個頂層標簽
(2)組件的樣式
設置組件的樣式: 內聯樣式,對象樣式,選擇器樣式
注意:在React和HTML5中設置樣式時的書寫格式是由區別的:
1.HTML5以分號;結尾,React以逗號,結尾
2.HTML5中key、value都不加引號,React中屬于JavaScript對象,key的名字不能出現分隔符“-”,需要使用駝峰命名法,
如果value為字符串,需要加引號。
3.HTML5中,value如果是數字需要帶單位,React中不需要帶單位
定義一個組件類,同時使用三種設置組件樣式的方式。div使用內聯樣式:設置背景顏色,邊框大小,邊框顏色;h1使用對象樣式:設置背景顏色,字體顏色;p使用選擇器樣式:設置字體大小
var ShowMessage = React.createClass({
render: function() {
return (
<div style={{backgroundColor:"yellow", borderWidth: 5, borderColor:"black", borderStyle:"solid"}}>
<h1 style={hStyle}>{this.props.firstRow}</h1>
// 在React中使用選擇器樣式設置組件樣式時,屬性名不能使用class,需要使用className替換。同樣的還有使用htmlFor替換for
<p className="pStyle">{this.props.secondRow}</p>
</div>
)
}
});
// 創建設置h1樣式對象Name
var hStyle = {
backgroundColor: "green",
color: "red"
}
ReactDOM.render(
<ShowMessage firstRow="你好" secondRow="小明"/>,
document.getElementById('root')
);
這里p使用的是選擇樣式,將樣式寫在index.css中,在使用的過程中進行導入
import './index.css';
.pStyle {
font-size: 20px;
}
在React中使用選擇器樣式設置組件樣式時,屬性名不能使用class,需要使用className替換。同樣的還有使用htmlFor替換for
(3)復合組件
復合組件 也稱為組合組件,創建多個組件合成一個組件。定義一個組件的WebShow。功能:輸出網站的名字和網址,網址是一個可以點擊的鏈接。
分析:定義一個組件WebName負責輸出網站名字,定義組件WebLink顯示網站的網址,并且可以點擊
// 定義WebName組件
var WebName = React.createClass({
render: function() {
return (
<h1>{this.props.webName}</h1>
)
}
});
// 定義WebLink組件
var WebLink = React.createClass({
render: function() {
return (
<a href={this.props.webLink}>{this.props.webLink}</a>
)
}
});
// 組合組件WebShow
var WebShow = React.createClass({
render: function() {
return (
<div>
<WebName webName={this.props.webName}/>
<WebLink webLink={this.props.webLink}/>
</div>
)
}
});
ReactDOM.render(
<WebShow webName="新浪" webLink="http://www.sina.com.cn"/>,
document.getElementById('root')
);
5.props
props是組件自身的屬性,一般用于嵌套的內外層組件中,負責傳遞數據(通常是由父層向子層組件傳遞)
注意:props對象中的屬性與組件的屬性一一對應,不要直接直接去修改props中屬性的值
...this.props
這個是props提供的語法糖,可以將父組件中的全部屬性都復制給子組件
下邊定義一個Link組件,Link組件只包含一個<a>
,我們不給<a>
設置任何屬性,所有屬性全部從父組件復制得到
var Link = React.createClass({
render: function () {
return <a {...this.props}>{this.props.name}</a>
}
});
ReactDOM.render(
<Link name="百度" />,
document.getElementById("root")
)
this.props.children
children組件是一個例外,不是跟組件的屬性對應的,它表示組件的所有子節點
下邊展示一種列表,在HTML5中有一種標簽:<ul> <ol> <li>
。定義一個列表組件,列表項中顯示的內容,以及列表項的數量都由外部決定。
var ListComponent = React.createClass({
render: function () {
return (
<ul>
{
// 列表項數量不確定,在創建模板時才能確定,利用this.props.children從父組件獲取需要展示的列表項內容
// 獲取到列表項內容后,需要遍歷children,逐行進行設置
// 使用React.Children.map方法 返回值:數組對象,這里數組中的元素是<li>
React.Children.map(this.props.children, function (child) {
// child是遍歷得到的父組件的子節點
return <li>{child}</li>
})
}
</ul>
);
}
});
ReactDOM.render(
(
<ListComponent>
<h1>百度文庫</h1>
<a >http://www.baidu.com</a>
<h1>百度文庫</h1>
<a >http://www.baidu.com</a>
<h2>百度文庫</h2>
</ListComponent>
),
document.getElementById("root")
);
屬性驗證
用來驗證外部設置的值是否符合組件對屬性類型的要求,也是組件類的屬性。用來驗證組件實例的屬性是否符合要求
var ShowTitle = React.createClass({
// 屬性驗證
propTypes: {
// title 必須為字符串
title: React.PropTypes.string.isRequired
},
render: function () {
return <h1>{this.props.title}</h1>
}
});
ReactDOM.render(
// 這里如果傳入title=1234,運行就會出錯,因為屬性驗證要求組件傳入的屬性時字符串類型的
<ShowTitle title="1234"/>,
document.getElementById("root")
);
設置組件屬性的默認值
通過實現組件的getDefaultProps方法,對屬性設置默認值
var ShowTitle = React.createClass({
getDefaultProps: function () {
return {
title: "小明"
}
},
render: function () {
return <h1>{this.props.title}</h1>
}
});
ReactDOM.render(
// 這里雖然沒有傳入屬性值,但是屬性設置了默認值,因此渲染結果是顯示出“小明”字樣
<ShowTitle />,
document.getElementById("root")
);
6.state
事件處理
定義一個組件,組件中包含一個button,給button綁定onClick事件
var MyButton = React.createClass({
// React中的事件名稱,首字母小寫,駝峰命名法
handleClick: function () {
alert("點擊按鈕觸發的效果")
},
render: function () {
return <button onClick={this.handleClick}>{this.props.buttonTitle}</button>
}
});
ReactDOM.render(
<MyButton buttonTitle="按鈕" />,
document.getElementById("root")
);
state狀態
state和props一樣,都是組件自身的屬性,通過調用this.state
下邊創建一個CheckButton組件,包含一個checkbox類型的<input>,復選框在選中和未選中兩種狀態下會顯示不同的文字,即根據狀態渲染
var CheckButton = React.createClass({
// 定義初始狀態
getInitialState: function () {
return {
// 在這個對象中設置的屬性,將會存儲在state中
isCheck: false
}
},
// 定義事件綁定的方法
handleChange: function () {
// 修改狀態值,通過this.state讀取設置的狀態值
this.setState({
isCheck: !this.state.isCheck
});
},
render: function () {
// 根據狀態值,設置顯示的文字
// 注意: 在JSX中不能直接使用if, 如果需要條件判斷需要在外邊寫個方法將結果傳進來就行,可以使用三目運算符
var text = this.state.isCheck ? "已選中" : "未選中";
return (
// 返回結果只能有一個根節點
<div>
<input type="checkbox" onChange={this.handleChange} />
{text}
</div>
);
}
});
ReactDOM.render(
<CheckButton />,
document.getElementById("root")
);
注意:
當state發生變化時,會調用組件內部的render方法
表單的基本使用
定義一個組件,將用戶在輸入框內輸入的內容進行實時顯示。組件在于用戶的交互過程中,存在狀態的變化,即輸入框的值
var Input = React.createClass({
getInitialState: function () {
return {
value: "請輸入"
};
},
// 輸入框的輸入回傳進來一個參數event
handeleChange: function (event) {
// 通過event.target.value讀取用戶輸入的值
this.setState({
value: event.target.value
});
},
render: function () {
var value = this.state.value;
return(
<div>
<input type="text" value={value} onChange={this.handeleChange} />
<p>{value}</p>
</div>
);
}
});
ReactDOM.render(
<Input />,
document.getElementById("root")
);
7.組件的生命周期
生命周期介紹
組件的生命周期可分成三個狀態:
- Mounting:組件掛載,已插入真實的DOM
- Updating:組件更新,正在被重新渲染
- Unmounting: 組件移出,已移出真實DOM
組件的生命周期可分成四個階段:創建、實例化、更新、銷毀
每種狀態對應的方法:
-
Mounting/組件掛在相關:
- componentWillMount:組件將要掛載。在render方法之前執行,但僅執行一次,即使多次重復渲染該組件,或者改變了組件的state
- componentDidMount:組件已經掛在。在render之后執行,同一個組件重復渲染只執行一次
-
Updating/組件更新相關:
- componentWillReceiveProps(object nextProps):已加載組件收到新的props之前調用,注意組件初始化渲染時不會執行
- shouldComponentUpdate(object nextProps, object nextState):組件判斷是否重新渲染時調用。該接口實際是在組件接收到了新的props或者新的state的時候會立即調用。返回一個Bool值。默認情況下是ture,這就是為什么在前文中說只要調用this.setState方法,就會重新渲染。當返回結果為true時會立即調用下邊另外兩個方法,如果返回false,則不會進行更新。
- componentWillUpdate(object nextProps, object nextState):組件將要更新
- componentDidUpdate(object prevProps, object prevState):組件已經更新
-
Unmounting/組件移除相關:
- componentWillUnmount:在組件要被移除之前的時間點觸發,可以利用該方法來執行一些必要的清理組件相關的工作
-
生命周期中與props和state相關:
- getDefaultProps 設置props屬性默認值
- getInitialState 設置state屬性初始值
生命周期各階段介紹
- 一、創建階段流程:
- 只調用getDefaultProps方法
- 二、實例化階段流程:
- getInitialState
- componentWillMount
- render
- componentDidMount
- 三、更新階段流程:
- componentWillReceiveProps
- shouldComponentUpdate 如果返回值是false,后三個方法不執行
- componentWillUpdate
- render
- componentDidUpdate
- 四、銷毀階段流程:
- 流程:componentWillUnmount
var Demo = React.createClass({
/*
一、創建階段
流程:只調用getDefaultProps方法
*/
getDefaultProps: function () {
// 正在創建類的時候被調用,設置this.props的默認值
console.log("getDefaultProps");
return {};
},
/*
二、實例化階段
流程: getInitialState
componentWillMount
render
componentDidMount
*/
getInitialState: function () {
// 設置this.state的默認值
console.log("getInitialState");
return null;
},
componentWillMount: function () {
// 在render之前調用
console.log("componentWillMount");
},
render: function () {
// 渲染并返回一個虛擬的DOM
console.log("render");
return <div>Hello React</div>
},
componentDidMount: function () {
// 在render之后調用 在該方法中,React會使用render方法返回的虛擬DOM對象創建真實的DOM結構
// 可以在這個方法中讀取DOM節點
console.log("componentDidMount");
},
/*
三、更新階段
流程:componentWillReceiveProps
shouldComponentUpdate 如果返回值是false,后三個方法不執行
componentWillUpdate
render
componentDidUpdate
*/
componentWillReceiveProps: function () {
console.log("componentWillReceiveProps");
},
shouldComponentUpdate: function () {
console.log("shouldComponentUpdate");
return true;
},
componentWillUpdate: function () {
console.log("componentWillUpdate");
},
componentDidUpdate: function () {
console.log("componentDidUpdate");
},
/*
四、銷毀階段
流程:componentWillUnmount
*/
componentWillUnmount: function () {
console.log("componentWillUnmount");
}
});
// 第一次創建并加載組件
ReactDOM.render(
<Demo />,
document.getElementById("root")
);
/*
上邊結果返回的是:
getDefaultProps
getInitialState
componentWillMount
render
componentDidMount
*/
// 更新渲染組件
ReactDOM.render(
<Demo />,
document.getElementById("root")
);
/*
更新渲染后的結果:
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
注意如果將shouldComponentUpdate的返回值設置成false,那么該方法以下的步驟將不會再執行
返回結果是:
componentWillReceiveProps
shouldComponentUpdate
*/
// 移出組件
ReactDOM.unmountComponentAtNode(document.getElementById("root"));
/*
移出組件后的結果:
componentWillUnmount
*/