react全家桶快餐進食指南

darklinda588發表於2018-07-06

emmmmm。。。。。。。。。。

如果有什麼說的不對的地方,歡迎評論告知。

=3333333=

先從最基礎的react說起吧,目前框架都屬於元件化的,但是更主要的目的是為了讓前端圍繞著資料邏輯來做頁面而並非原先的去操作dom的思想,三大框架目前都是往一個方向去。不過相比其他,react主打是diff演算法處理dom,所以掌握他的生命週期去處理好資料才是我們最初應該學習的東西。

react

最常用的就是react.Component
談一下他的生命週期吧。
假如我頁面有一個首頁,我們現在要做頂部的導航欄,那麼我們現在去寫一個頂部導航的元件。
假設這個頂部的導航,每個人許可權不同,看到的東西不一樣,那麼這個導航是通過請求資料來實現的。

來,先熟悉

生命週期。

掛載時期會執行的(可以理解為這個元件丟到頁面時候會執行,並且只執行一次的)。

constructor() // 建構函式,一般我會在這裡去定當前元件的state初始化

componentWillMount() // 掛載之前,在17之後改名下面一條

UNSAFE_componentWillMount() // 上面掛載前馬上要更改的名字。
//這個是唯一會在服務端呼叫的生命週期鉤子,在這裡設定一些東西不會導致元件重新渲染,
//所以這裡最好不要隨意進行一些元件需要資料的請求。

render() // 這個元件需要輸出的東西,按道理來說都是一些jsx之類的,
//如果你輸出的是字串和數字,則會變成text node, 
//如果輸出的是布林值的false,或者null,就會不進行渲染。

componentDidMount() // 這裡就是元件掛載時候最後觸發的一個生命週期了。
// 因為這個裡面請求資料會讓元件重新渲染,所以一般資料放在這裡進行請求。

然後這個元件因為資料變化也會重新渲染,一種是props改變的時候(或者父元件重新渲染的時候),一種是自己的state改變的時候。

props改變的時候會執行的生命週期

UNSAFE_componentWillReceiveProps(nextProps) // 這個生命週期在17版之前叫componentWillReceiveProps
// 一般是在父元件更新的時候,或者props改變的時候會觸發的,用來根據props更改而改本元件state用的
// 官方目前推薦用下一條去替換他

static getDerivedStateFromProps(nextProps, prevState) // 接收到新的props或者父元件重新渲染的時候,都會呼叫。
// 如果你只想處理變化,就要比較新舊值
// 作用跟上面一條是一樣的,props改變時候要改state就在這裡做

shouldComponentUpdate(nextProps, nextState) // 這裡可以通過返回false,來阻止重新渲染
// 預設為true,若shouldComponentUpdate()返回false,
//而後UNSAFE_componentWillUpdate(),render(), 和 componentDidUpdate()將不會被呼叫

UNSAFE_componentWillUpdate() // 17版以前叫componentWillUpdate
// 在收到新的state或者props的時候,渲染前被立即呼叫
//不要在這裡setState,不要在這裡setState,不要在這裡setState,

render() // 當然少不了輸出需要顯示的東西啦

getSnapshotBeforeUpdate() // 在最新的渲染輸出提交給DOM前將會立即呼叫
// 為了支援非同步渲染,如果在componentWillUpdate處理的一些事情,可能會有延遲滯後
// 這一生命週期返回的任何值將會 作為引數被傳遞給componentDidUpdate()。

componentDidUpdate(prevProps, prevState) // 終於說到最後一個了,我擦啦
// 更新發生後立即被呼叫
// 這也是一個適合傳送請求的地方,要是你對比了當前屬性和之前屬性(例如,如果屬性沒有改變那麼請求也就沒必要了),不然就迴圈給你看,嘿嘿嘿嘿嘿嘿

然後就是state更改的時候了,懶得打了,就是上面props更改時候的一些生命週期去掉UNSAFE_componentWillReceiveProps(nextProps)或者static getDerivedStateFromProps(nextProps, prevState),直接從shouldComponentUpdate開始。

最後元件準備被移除的時候

componentWillUnmount()
// 在元件被解除安裝和銷燬之前立刻呼叫。可以在該方法裡處理任何必要的清理工作
// 例如解繫結時器,取消網路請求,清理任何在componentDidMount環節建立的DOM元素。

捕捉錯誤的生命週期

componentDidCatch(error, info)
// 列印它們之下元件裡的錯誤,不能捕捉它自己內部的錯誤。
// 在這裡是用來處理錯誤的,不要嘗試用這個去處理資料

好了,生命週期大致就是這些,估計看完也困了。
我們假如要做一個頂部導航,那麼(敲黑板)重點就在於這個元件怎麼請求,請求完了啥時候往裡面丟,頁面怎麼處理之類的。

其實總結起來也比較簡單,步驟如下

  1. constructor() 定初始化的state,裡面有一個我們需要迴圈展示出來的list用來儲存導航
  2. render() 裡面寫好迴圈state裡面的list等展示效果
  3. componentDidMount() 根據當前使用者的一些資訊去請求資料,並且處理完setState塞入list裡面
  4. shouldComponentUpdate() 如果他的父元件會更新,但是他不需要做過多的重複渲染,則在這裡判斷新舊值,考慮是否要重新渲染

另外有的小夥伴說,React.PureComponent可以幫你處理一些 shouldComponentUpate()新舊值的判斷是否要重新渲染,不過這個只會對物件進行淺對比
如果物件包含複雜的資料結構,那麼可能會導致他無法渲染出你要的最新的資料,React.PureComponent 的 shouldComponentUpate() 會忽略整個元件的子級。請確保所有的子級元件也是”Pure”的。


關於redux的資料流

說簡單一點,其實就是

  1. 我往專案根部建立一個store(儲存資料的東西)
  2. 觸發action
  3. action告訴reducer我要改資料了!
  4. reducer改完了資料頁面也同時拿到了

action => reducer => store

不過因為redux不希望有一些副作用的資料產生,所以我們要在這裡面請求資料,就需要一些中介軟體。
目前比較大眾的有倆。
redux-saga和redux-thunk

先大致介紹一下

redux-thunk

說簡單一些,就是讓action中可以請求非同步操作,請求到了資料再執行reducer存入store裡面。

引入方法

import thunkMiddleware from `redux-thunk`
import { Provider } from `react-redux`
import { createStore, applyMiddleware } from `redux`
import { Reduces } from `./store/index.js` // 引入所有的reduces

const store = createStore(
  Reduces,
  applyMiddleware(
    thunkMiddleware // 允許 dispatch() 函式
  )
)

<Provider store={store}> // 丟到裡面去
    <Router>
    </Router>
 </Provider>


然後在action裡面,就可以

  /**
   * 獲取使用者訂單資訊
   * @param {String} type 使用者訂單的請求型別
   * @return {dispatch} dispatch 返回撥用新的action方法
   */
  getUserOrderList(type) {
    return dispatch => {
    // 這個OrderModel是我自己專案所有訂單請求都放在裡面的,其實就相當與寫一個fetch,然後then的處理他
      return OrderModel.orderlist({
        status: type
      }).then(response => {
        // 這裡在存入store裡面去,這裡一般我會寫一個公用的dispatch的方法進行丟入
      })
    }
  }

然後用dva的朋友一般用的都是

redux-saga

這個其實我瞭解的並不深,就拿官網的事例來用一下

import { call, put, takeEvery, takeLatest } from `redux-saga/effects`
import Api from `...`

// worker Saga : 將在 USER_FETCH_REQUESTED action 被 dispatch 時呼叫
function* fetchUser(action) {
   try {
       // call這裡進行請求資料,拿到的資料丟到user裡面
      const user = yield call(Api.fetchUser, action.payload.userId);
      // 開始匹配type,進行資料更改在這裡
      yield put({type: "USER_FETCH_SUCCEEDED", user: user});
   } catch (e) {
      yield put({type: "USER_FETCH_FAILED", message: e.message});
   }
}

這裡放上兩個文件供參考

redux-saga
redux-thunk

bug

一般玩react最容易遇到的坑,就是如何處理好資料,搭配生命週期,剛開始可能會因為沒處理好資料,導致元件無內容報錯,也有迴圈不加key等。

感覺報錯最多的可能性應該是這個key了。
當迴圈的時候,或者使用table表單的時候,特別是antd裡面的table,要仔細看文件,需要key的時候一定要加上。

route

route目前用的比較多的是兩種
BrowserRouter和HashRouter

HashRouter

這個就比較醜了,但是路由都在前端,所有的頁面都是用#後面帶上一些東西,前端自己做管理就好了。
HashRouter 使用 URL 的 hash (例如:window.location.hash) 來保持 UI 和 URL 的同步。
不過像描點就不要想啦。

import { HashRouter } from `react-router-dom`

<HashRouter>
  <App/>
</HashRouter>

BrowserRouter

這個就是使用 HTML5 提供的 history API 來處理路由,所有的頁面都是真實路徑,需要後端配置所有請求頁面都指向我們的主頁面。

import { BrowserRouter } from `react-router-dom`

<BrowserRouter>
  <App/>
</BrowserRouter>

跳轉路由直接頁面裡面跳轉,可以用下面的方法

import { Link } from `react-router-dom`

<Link to="/about">關於</Link>

如果是在js裡面想跳轉,則

this.props.history.push() // 或者replace,過著go()啥的

就可以進行跳轉了,不過元件裡面要拿到父元件的props需要繼承一下

比如

<子元件 {...this.props}></子元件>

這樣就可以把父元件的props全部丟到子元件裡面去 =3=

最後把專案的一些需要的文件整理了一下

相關文章