初識時下熱門框架 - React

React 做爲時下最流行的框架之一,不能否認其在前端框架當中的地位,不少的項目也都在使用 React;做爲一名 Front-end engineer,學習 React 不管是對於項目開發仍是自身的水平都會有必定程度的幫助。

最近開始簡單的學習了 React,因此在此簡單的總結一下。css

原文地址:初識 Reacthtml

關於腳手架的簡單使用

在網上看到了不少 React 的腳手架工具,這裏我使用的是 create-react-app ,建立項目也比較簡單。

  • 安裝 create-react-app
npm install -g create-react-app

  • 建立一個 React 項目
create-react-app my-app

  • 啓動項目
npm start

項目結構

項目建立後,如圖,目錄結構也比較清晰:前端

clipboard.png

  • node_modules:存放項目依賴
  • public:存放項目入口文件
  • src:存放項目代碼以及項目資源
  • package.json:項目依賴管理

關於目錄結構,能夠依據實際項目需求進行劃分,以下圖結構:node

clipboard.png

  • assets -- 存放項目靜態資源
  • components -- 存放組件
  • css -- 樣式表
  • page -- 存放各個頁面組件(也可稱做父組件)

隨着項目的複雜程度,項目結構劃分的也更可加精細。react

React 簡單上手

寫了一些 demo,整體感受 React 仍是頗有意思的,由於以前接觸過 Vue 的關係,因此以爲上手仍是相對簡單的,固然 React 和 Vue 也有不少不一樣點,如 React 組件有獨立狀態機,大大提升了組件的獨立性、可操做性;React 支持 Jsx 語法,對於開發者來講能夠必定程度提升開發效率;再配合 ES6 語法, 代碼寫起來會很舒服。ios

固然,隨着對 React 更加深刻的學習與瞭解,學習的梯度也會愈來愈高。做爲開發者咱們都知道 React 強大完整的生態體系,它已不僅僅是一個框架,而是已經發展爲一個行業的解決方案。git

簡單總結上手碰到的坑

  1. 關於 getInitialState
  2. getDefaultProps 的疑惑
  3. 關於請求數據
  4. 關於事件傳參
  5. React 中的 this
  6. 關於組件的生命週期
  7. 父子組件之間的傳值
  8. react-router 的使用

關於 getInitialState

一開始看了阮大神的文章,卻不知在 ES6 中須要在 constructor 中定義 state ,致使了程序報錯:github

constructor(props) {
        super(props);
        this.state = {flag: false};
        this.handle = () =>{
            //setState 是異步執行的,render時纔會調用,能夠寫入回調函數
            this.setState({flag: !this.state.flag}, () => {
                //code
            });

        }
    }

getDefaultProps 的疑惑

在建立了一個組件後,使用 getDefaultProps 設置默認屬性時,控制檯報了這樣一條警告:web

clipboard.png

經查閱後瞭解到: getDefaultProps 方法是用在使用 React.createClass 方式建立組件的,應該使用 ES6 語法:ajax

static defaultProps = {
    content: ''
}

關於請求數據

React 請求數據有不少方法如 $.ajax(), fetch api, axios, ajax() 等等,這裏我簡單使用了一下 fetch() 方法,fetch() 方法返回了一個 Promise 對象,reslove 時會返回 response 對象,一個最基本的用法:

fetch(api)
  .then(function(response) {
    return response.json()
  }).then(function(json) {
    //resolve callback
    console.log('parsed json', json)
  }).catch(function(ex) {
    //reject callback
    console.log('parsing failed', ex)
  })

固然,由於 babel 對部分 ES7 的支持,也可使用 await/async 進行請求,把異步代碼當作同步代碼來寫,開發體驗要比寫回調好不少

//必須聲明 async
async getData() {
    let response = await fetch(api)
    let data = await response.json();
    console.log(data);
}

注:在請求本地文件時需將資源放到 public 目錄下,請求路徑爲 '/xx.json',也可使用 import 引入文件。


關於事件傳參

在爲元素綁定事件的過程當中,若是須要傳參,可使用 bind 方法進行傳參:

<span className="g-data" onClick={this.handle.bind(this, this.props.source)}> 
    //code
 </span>

其中,bind 的第一個參數 this 是指改變函數運行時的指針,如:在 render() 中使用該方法,則 this 指向組件的實例,這樣才能準確訪問組件的屬性和方法。

一樣的,也可使用箭頭函數進行傳參:

<span className="g-data" onClick={ () => this.handle(this.props.source) }> 
    //code
 </span>

React 中的 this

一開始在我爲組件綁定事件的時候,發如今綁定事件中沒法拿到 props 屬性:

<span className="g-data" onClick={this.handle}> 
    //code
 </span>

最初個人理解是:綁定事件的函數中, this 應該是指向 class 建立的實例的。事實證實,個人理解是錯誤的:事件的回調函數是在全局環境下執行的,也就是 window 。因而我在 handle 中試着輸出 this :

handle() {
    console.log(this); //undefined
}

輸出了 undefined,又是一個大寫的問號,因而我找了一下 ES6 的相關規範:在 class 中,定義類的時候默認使用嚴格模式,而在嚴格模式下,this 不能指向全局變量,所以變成了 undefined。因此,爲了解決這個問題,大體有以下幾種辦法:

  • 在組件渲染時綁定 this
<span className="g-data" onClick={this.handle.bind(this)}> 
    //code
 </span>
  • 在 constructor 內綁定
constructor() {
    this.handle = this.handle.bind(this);
}
  • 使用箭頭函數綁定
handle = () => {

}

或者在 DOM 結構中寫箭頭函數

<span className="g-data" onClick= { () => this.handle() } > 
    //code
 </span>

關於組件的生命週期

每個組件都有幾個你能夠重寫以讓代碼在處理環節的特定時期運行的「生命週期方法」。方法中帶有前綴 will 的在特定環節以前被調用,而帶有前綴 did 的方法則會在特定環節以後被調用。如:

  • componentWillMount( )

表示組件即將渲染以前會調用,即在 render() 以前調用。

  • componentDidMount( )

表示組件渲染完成當即調用,這個生命週期設置狀態會觸發從新渲染。

  • componentWillUnmount( )

表示組件將要被移除以前調用,在這裏能夠進行一系列的清理工做。

更多組件生命週期請移步 React 官方文檔

父子組件之間的傳值

  • 父組件給子組件傳值

在父組件中爲子組件添加屬性和屬性值,在子組件中經過 props 屬性得到父組件對應的屬性值。

//父組件
<div>
    <child title="This is title" />
</div>

//子組件
<div>{this.props.title}</div>
  • 子組件給父組件傳值

能夠在父組件的子組件中添加一個回調函數;子組件中設置狀態值,當子組件中的值改變時,修改狀態值會觸發重渲,經過 props 拿到父組件的回調函數,並將新的狀態值做爲參數傳入,這樣父組件就能夠拿到子組件的值並進行後續操做。

//父組件
    constructor(props) {
        super(props)
        this.state = {
            childState: ''
        }
    }

    handleChange(childState) {
        this.setState({
            childState: childState
        })
    }

    render() {
        return (
            <div className="parent">
                <Child callBack={this.handleChange.bind(this)} />
            </div>
        )
    }
    
    //子組件
    constructor(props) {
        super(props)
        this.state = {
            childState: 'childState'
        }
    }

    handleChange(e) {
        //setState 是異步的,因此要先拿到 childState 的值,
        //或者寫入 setState 的回調函數中
        var childState = e.target.value
        this.setState({
            childState : e.target.value
        })
        this.props.callBack(childState)
    }

    render() {
        return (
            <div className="child">
                <input type="text" onChange={this.handleChange.bind(this)} />
            </div>
        )
    }

react-router 的使用

一開始的時候,參考了一些文章試着使用了一下 react-router ,結果一直報錯,後來發現版本更新致使部分語法改變,這裏我使用的是 4.x 版本,一個比較基本的路由實現:
首先,引入 react-router:

import {
    BrowserRouter as Router,
    Route,
    Link
} from 'react-router-dom

接下來進行路由配置,告訴路由如何進行匹配以及匹配後如何執行代碼:

<Router>
    <div>
        <Link to="/">Home</Link>
        <Link to="/About">About</Link>
        
        //exact(bool):爲true時,則要求路徑與location.pathname必須徹底匹配;
        <Route exact path="/" component={Home}/>
        <Route path="/About" component={About}/>
    </div>
</Router>

在路由跳轉到另外一個頁面時,若是當前頁面存在路由跳轉,則涉及到路由嵌套:

render() {
    let match = this.props.match
    return (
        <Router>
            <div>
                <Link to={match.url}>Tab One</Link>
                <Link to={`${match.url}/Two`}>Tab Two</Link>
                <Route exact path={match.url} render={()=>(<h3>1</h3>)} />
                //:param 能夠理解爲一種匹配模式,能夠經過 params 拿到對應屬性值
                <Route path={`${match.url}/:param`} component={Topic} />
            </div>
        </Router>
    )
}

match 對象中存儲着路由路徑的相關信息,經過 match 對象能夠拿到一級路徑,而後再根據二級路徑進行匹配便可。

有些狀況,在進行路由跳轉時須要傳遞一些參數,當參數比較多的時候,經過路由路徑傳遞參數就不是一個好的選擇了,能夠經過 query/state 傳參:

//經過 location 對象取值
<Link to={{pathname:'/Message',query:{name:'react'},state:{name:'react'}}} >Message</Link>

//使用 js 傳參
this.props.router.push({pathname:'/Message',query:{name:'react'}})

小結

經過簡單上手 React ,我以爲用來開發項目很方便, 由於 React 使用了 virtual dom 因此在性能方面也比較給力,加上組件化開發、Jsx 和 ES6 語法的加持以及完善的生態體系,我想這大概就是 React 成爲時下熱門框架的緣由之一吧。

參考文獻

  1. React 入門實例教程
  2. React - 用於構建用戶界面的 JavaScript 庫
  3. 從 React 綁定 this,看 JS 語言發展和框架設計
  4. 深刻淺出Fetch API
  5. 類 - JavaScript | MDN
  6. React 組件之間如何交流
  7. React Router 中文文檔
相關文章
相關標籤/搜索