1. 程式人生 > >React框架快速入門

React框架快速入門

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元素物件;
<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
  • 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)。

這裡寫圖片描述