React框架快速入門
阿新 • • 發佈:2019-01-23
React快速入門
ReactJS介紹
ReactJS是什麼?
- 1). Facebook開源的一個js庫;
- 2). 一個用於動態構建使用者介面的js庫;
- 3). React的特點;
- Declarative(宣告式編碼);
- Component-Based(元件化編碼);
- Learn Once, Write Anywhere(支援客戶端與伺服器渲染);
- 高效;
- 單向資料流;
React高效的原因
- 1). 虛擬(virtual)DOM, 不總是直接操作DOM,減少頁面更新次數;
- 2). 高效的DOM Diff演算法, 最小化頁面重繪;
React的幾個重要概念
- 1.模組與元件
- 模組:
- 理解: 向外提供特定功能的js程式, 一般就是一個js檔案
- 為什麼: js程式碼越多越複雜了;
- 作用: 簡化js的編寫, 閱讀, 提高執行效率
- 元件:
- 理解: 用來實現特定功能效果的程式碼集合(html/css/js)
- 為什麼: 一個介面的功能更復雜
- 作用: 複用, 簡化專案編碼, 提高執行效率
- 模組:
2.模組化與元件化
- 模組化:當應用的js都以模組來編寫的, 這個應用就是一個模組化的應用;
- 元件化:當應用是以多元件的方式實現功能, 這樣應用就是一個元件化的應用;
宣告式程式設計和指令式程式設計
- 宣告式程式設計:只關注做什麼, 而不關注怎麼做(流程), 類似於填空題,陣列中常見宣告式方法:map() / forEach() / find() / findIndex();
- 指令式程式設計:要關注做什麼和怎麼做(流程), 類似於問答題;
var arr = [1, 3, 5, 7] // 需求: 得到一個新的陣列, 陣列中每個元素都比arr中對應的元素大10: [11, 13, 15, 17] // 指令式程式設計 var arr2 = [] for(var i =0;i<arr.length;i++) { arr2.push(arr[i]+10) } console.log(arr2) // 宣告式程式設計 var arr3 = arr.map(function(item){ return item +10 }) // 宣告式程式設計是建立指令式程式設計的基礎上
React的使用
與使用有關的理解
JSX
1). 理解
- 全稱: JavaScript XML;
- react定義的一種類似於XML的JS擴充套件語法: XML+JS;
作用: 用來建立react虛擬DOM(元素)物件;
var ele = <h1>Hello JSX!</h1>;
- 注意1: 它不是字串, 也不是HTML/XML標籤
- 注意2: 它最終產生的就是一個JS物件
2). 編碼相關
- 基本語法規則
- 遇到 <開頭的程式碼, 以標籤的語法解析:html同名標籤轉換為html同名元素, 其它標籤需要特別解析;
- 遇到以 { 開頭的程式碼,以JS的語法解析:標籤中的js程式碼必須用{}包含;
- js中直接可以套標籤, 但標籤要套js需要放在{}中;
- 在解析顯示js陣列時, 會自動遍歷顯示;
把資料的陣列轉換為標籤的陣列:
var liArr = dataArr.map(function(item, index){ return <li key={index}>{item}</li> })
babel.js的作用
- 瀏覽器的js引擎是不能直接解析JSX語法程式碼的, 需要babel轉譯為純JS的程式碼才能執行
- 只要用了JSX,都要加上type=”text/babel”, 宣告需要babel來處理
- 基本語法規則
3). 注意:
- 標籤必須有結束;
- 標籤的class屬性必須改為className屬性;
- 標籤的style屬性值必須為: {{color:’red’, width:12}};
虛擬DOM
1). React提供了一些API來建立一種
特別
的一般js物件;//建立的就是一個簡單的虛擬DOM物件 var element = React.createElement('h1', {id:'myTitle'}, 'hello');
2). 虛擬DOM物件最終都會被React轉換為真實的DOM;
- 3). 我們編碼時基本只需要操作react的虛擬DOM相關資料, react會轉換為真實DOM變化而更新介面;
4).建立虛擬DOM的2種方式:
1). 純JS(一般不用):
// 純JS方式 const msg = 'I like you'; const myId = 'atguigu'; const vDOM1 = React.createElement('h2',{id:myId},msg);
2). JSX方式:
// jsx方式建立虛擬dom元素物件 const vDOM2 = <h3 id={myId.toUpperCase()}>{msg.toLowerCase()}</h3>
5).渲染虛擬DOM(元素)
- 1). 語法: ReactDOM.render(virtualDOM, containerDOM) :
- 2). 作用: 將虛擬DOM元素渲染到真實容器DOM中顯示
- 3). 引數說明
- 引數一: 純js或jsx建立的虛擬dom物件
- 引數二: 用來包含虛擬DOM元素的真實dom元素物件(一般是一個div)
// 渲染到真實的頁面中 ReactDOM.render(vDOM1,document.getElementById('example1')); ReactDOM.render(vDOM2,document.getElementById('example2'));
寫個Hello world
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>02_JSX_DEMO</title>
</head>
<body>
<ul>
<li>A</li>
<li>B</li>
<li>C</li>
</ul>
<hr>
<div id="example1"></div>
<div id="example2"></div>
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script type="text/babel">
/*
功能: 動態展示列表資料
*/
/*
技術點:
1). 使用JSX建立虛擬DOM
2). React能自動遍歷顯示陣列中所有的元素
3). array.map()的使用
*/
//資料的陣列
var names = ['Tom2', 'Jack2', 'Bob2'];
//資料的陣列——>標籤陣列
var lis = [];
names.forEach((item,index)=>lis.push(<li key={index}>{item}</li>));
//建立虛擬的DOM
const ul=<ul>{lis}</ul>;
// 將虛擬的Dom渲染到頁面中的某個DOM元素中
ReactDOM.render(ul,document.getElementById('example1'))
const ul2 = <ul>{names.map((name,index)=><li key={index}>{name}</li>)}</ul>
ReactDOM.render(ul2, document.getElementById('example2'))
</script>
</body>
</html>
React元件
自定義元件
一、定義元件
- 方式1:工廠(無狀態)函式(簡單元件,推薦使用);
// 方式一:工廠函式,推薦使用
function MyComponent() {
return <h2>工廠函式</h2>
}
- 方式2:ES6類語法;
// 方式二:ES6類語法(複雜元件,推薦使用)
class MyComponent2 extends React.Component{
render(){
return <h2>ES6的語法</h2>
}
}
- 方式3:ES5老語法(不推薦使用了)
// 方式三:ES5的老語法
const MyComponent3 = React.createClass({
render(){
return <h2>EES5老語法(不推薦使用了)</h2>
}
})
二、渲染元件標籤
//語法規則
ReactDOM.render(<MyComponent/>, document.getElementById('example'));
- 注意:
- 1). 返回的元件類必須首字母大寫;
- 2). 虛擬DOM元素必須只有一個根元素;
- 3). 虛擬DOM元素必須有結束標籤;
- ReactDOM.render()渲染元件標籤的基本流程:
- 1). React內部會建立元件例項物件;
- 2). 得到包含的虛擬DOM並解析為真實DOM;
- 3). 插入到指定的頁面元素內部;
// 二:渲染元件標籤
ReactDOM.render(<MyComponent/>,document.getElementById('example1'));
ReactDOM.render(<MyComponent2/>,document.getElementById('example2'));
ReactDOM.render(<MyComponent3/>,document.getElementById('example3'));
元件的三大屬性
元件的3大屬性之一: props屬性
- 1.每個元件物件都會有props(properties的簡寫)屬性;
- 2.元件標籤的所有屬性都儲存在props中;
- 3.內部讀取某個屬性值: this.props.propertyName;
- 4.作用: 通過標籤屬性從元件外向元件內傳遞資料(只讀);
- 5.對props中的屬性值進行型別限制和必要性限制;
// 對標籤屬性進行限制
Person.propTypes = {
name:React.PropTypes.string.isRequired,
sex:React.PropTypes.string,
age:React.PropTypes.number
}
- 6.擴充套件屬性: 將物件的所有屬性通過props傳遞
<Person {...person}/>
//具體如下:
ReactDOM.render(<Person {...person}/>,document.getElementById('example'))
- 7.預設屬性值
// 指定屬性的預設值
Person.defaultProps = {
sex:'男',
age:18
}
- 8.元件類的建構函式
constructor (props) {
super(props)
console.log(props) // 檢視所有屬性
}
元件的3大屬性之二: refs屬性
- refs屬性
- 1). 元件內的標籤都可以定義ref屬性來標識自己;
- 2). 在元件中可以通過this.refs.refName來得到對應的真實DOM物件;
- 3). 作用: 用於操作指定的ref屬性的dom元素物件(表單標籤居多);
<input ref='username'>
this.refs.username //返回input物件
- 事件處理
- 1). 通過onXxx屬性指定元件的事件處理函式(注意大小寫)
- React使用的是自定義(合成)事件, 而不是使用的DOM事件;
- React中的事件是通過委託方式處理的(委託給元件最外層的元素);
- 2). 通過event.target得到發生事件的DOM元素物件;
- 1). 通過onXxx屬性指定元件的事件處理函式(注意大小寫)
<input onFocus={this.handleClick}/>
handleFocus(event) {
event.target //返回input物件
}
強烈注意
- 1). 元件內建的方法中的this為元件物件;
2). 在元件中自定義的方法中的this為null;
強制繫結this;
this.change = this.change.bind(this);
箭頭函式(ES6模組化編碼時才能使用);
- 問題: 如何給一個函式強制指定內部的this?
元件的3大屬性之三: state屬性
- 1). 元件被稱為”狀態機”, 通過更新元件的狀態值來更新對應的頁面顯示(重新渲染)
- 2). 初始化狀態:
constructor (props) {
super(props)
this.state = {
stateProp1 : value1,
stateProp2 : value2
}
}
3). 讀取某個狀態值
this.state.statePropertyName
4). 更新狀態—->元件介面更新
this.setState({ stateProp1 : value1, stateProp2 : value2 })
5). 問題: 請區別一下元件的props和state屬性?
React其他操作
雙向繫結
- React是一個單向資料流
- 可以自定義雙向資料流元件(受控元件),需要通過onChange監聽手動實現;
<script type="text/babel">
class Control extends React.Component{
constructor(props){
super(props)
//初始化狀態
this.state = {
msg:'ATGUIGU'
}
this.handleChange = this.handleChange.bind(this)
}
handleChange(event){
//得到最新的state的值
const msg=event.target.value;
// console.log(event.target)
// console.log(event.target.value)
//更新狀態
this.setState({msg})
}
render(){
const {msg} = this.state
return(
<div>
<input type="text" value={msg} onChange={this.handleChange}/>
<p>{msg}</p>
</div>
)
}
}
ReactDOM.render(<Control/>,document.getElementById('example'))
</script>
元件生命週期
- 1.元件的三個生命週期狀態:
- Mount:插入真實 DOM
- Update:被重新渲染
- Unmount:被移出真實 DOM - 2.React 為每個狀態都提供了兩種勾子(hook)函式,will 函式在進入狀態之前呼叫,did 函式在進入狀態之後呼叫;
- componentWillMount();
- componentDidMount() : 已插入頁面真實DOM, 在render之後才會執行;
- componentWillUpdate(object nextProps, object nextState);
- componentDidUpdate(object prevProps, object prevState);
- componentWillUnmount();
3.生命週期流程:
第一次初始化渲染顯示: render()
- constructor(): 建立物件初始化state
- componentWillMount() : 將要插入回撥函式;
- render() : 用於插入虛擬DOM回撥函式;
- componentDidMount() : 已經插入回撥函式;在此方法中啟動定時器/繫結監聽/傳送Ajax請求;
每次更新state: this.setSate()
- componentWillUpdate() : 將要更新回撥函式;
- render() : 更新(重新渲染);
- componentDidUpdate() : 已經更新回撥;
- 刪除元件
- ReactDOM.unmountComponentAtNode(div): 移除元件;
- componentWillUnmount() : 元件將要被移除回撥;
- 3.常用的方法
- render(): 必須重寫, 返回一個自定義的虛擬DOM;
- constructor(): 初始化狀態, 繫結this(可以箭頭函式代替);
- componentDidMount() : 只執行一次, 已經在dom樹中, 適合啟動/設定一些監聽;
- 4.注意:
- 一般會在componentDidMount()中: 開啟監聽, 傳送ajax請求;
- 可以在componentWillUnmount()做一些收尾工作: 停止監聽;
- 生命週期還有一個方法(後面需要時講): componentWillReceiveProps;
//測試
class MyComponent extends React.Component{
constructor(props){
super(props)
this.state = {
msg:'這只是一句話而已'
}
}
componentWillMount(){
console.log('componentWillMount')
//啟動一個定時器,更新狀態
setTimeout(function () {
this.setState({msg:Date.now()})
}.bind(this),2000)
//啟動一個定時器,移除元件
setTimeout(function () {
ReactDOM.unmountComponentAtNode(document.getElementById('example'))
},4000)
}
render(){
console.log('render()')
const {msg}=this.state
return <p>{msg}</p>
}
componentDidMount(){
console.log('componentDidMount')
}
componentWillUpdate () {
console.log('componentWillUpdate')
}
componentDidUpdate () {
console.log('componentDidUpdate')
}
componentWillUnmount () {
console.log('componentWillUnmount')
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('example'))
//一個小練習,文字漸隱
class Fade extends React.Component{
constructor(props){
super(props)
this.state={
opacity:1
}
}
componentDidMount(){
//在此方法中啟動定時器/繫結監聽/傳送Ajax請求
this.intervalId=setInterval(function () {
//儲存到當前元件物件中
let {opacity}=this.state
//操作當前的資料。
opacity -= 0.1
// 更新狀態
this.setState({opacity})
}.bind(this),500)
}
componentWillUnmount(){
//清除定時器/解除監聽
clearInterval(this.intervalId)
}
removeComp(){
//移除元件
ReactDOM.unmountComponentAtNode(document.getElementById('example'))
}
render(){
return(
<div>
<p style={{opacity:this.state.opacity}}>{this.props.content}</p>
<button onClick={this.removeComp}>移除元件</button>
</div>
)
}
}
ReactDOM.render(<Fade content={'為什麼不過節?'}/>,document.getElementById('example'))
React傳送ajax請求
- 1). React沒有ajax模組,所以只能整合其它的js庫(如jQuery/axios/fetch), 傳送ajax請求;
- 2). 整合其它的js庫(如axios/fetch/jQuery/), 傳送ajax請求
- axios
- 封裝XmlHttpRequest物件的ajax
- promise
- 可以用在瀏覽器端和伺服器
- fetch
- 不再使用XmlHttpRequest物件提交ajax請求
- fetch就是用來提交ajax請求的函式, 只是新的瀏覽才內建了fetch
- 為了相容低版本的瀏覽器, 可以引入fetch.js
- axios
- 3). 在哪個方法去傳送ajax請求
- 只顯示一次(請求一次): componentDidMount()
- 顯示多次(請求多次): componentWillReceiveProps()
//做一個跳轉頁面
<script src="../js/react.js"></script>
<script src="../js/react-dom.js"></script>
<script src="../js/babel.min.js"></script>
<script src="https://cdn.bootcss.com/axios/0.16.2/axios.js"></script>
<script type="text/babel">
class UserLastGist extends React.Component {
constructor (props) {
super(props)
this.state = {
url: null
}
}
componentDidMount () {
// 傳送ajax請求
const url = `https://api.github.com/users/${this.props.username}/gists`
axios.get(url)
.then(response => {
console.log(response)
// 讀取響應資料
//0索引位代表最後更新的網頁內容
const url = response.data[0].html_url
// 更新狀態
this.setState({url})
})
.catch(function (error) {
console.log('----', error);
})
}
render () {
const {url} = this.state
if(!url) {
return <h2>loading...</h2>
} else {
return <p>{this.props.username}'s last gist is <a href={url}>here</a> </p>
}
}
}
UserLastGist.propTypes = {
username: React.PropTypes.string.isRequired
}
ReactDOM.render(<UserLastGist username="octocat"/>, document.getElementById('example'))
</script>
虛擬dom
- 1). 虛擬DOM是什麼?
- 一個虛擬DOM(元素)是一個一般的js物件, 準確的說是一個物件樹(倒立的);
- 虛擬DOM儲存了真實DOM的層次關係和一些基本屬性,與真實DOM一一對應;
- 如果只是更新虛擬DOM, 頁面是不會重繪的;
- 2). Virtual DOM 演算法的基本步驟
- 用JS物件樹表示DOM樹的結構;然後用這個樹構建一個真正的DOM樹插到文件當中
- 當狀態變更的時候,重新構造一棵新的物件樹。然後用新的樹和舊的樹進行比較,記錄兩棵樹差異
- 把差異應用到真實DOM樹上,檢視就更新了
- 3). 進一步理解
- Virtual DOM 本質上就是在 JS 和 DOM 之間做了一個快取。
- 可以類比 CPU 和硬碟,既然硬碟這麼慢,我們就在它們之間加個快取:既然 DOM 這麼慢,我們就在它們 JS 和 DOM 之間加個快取。CPU(JS)只操作記憶體(Virtual DOM),最後的時候再把變更寫入硬碟(DOM)。