super(props)用來調用基類的構造方法(constructor())。
同時,也將父組件的props注入給子組件,供子組件讀取(組件總props只讀不可變,state可變)
而constructor()用來做一些組件的初始化工作,如定義this.state的初始內容。
componentWillMount:
在組件掛載到DOM前調用,且只會被調用一次。
在這邊調用this.setState不會引起組件重新渲染,也可以把寫在這邊的內容提前放到constructor()中,所以項目中很少用。
render:
根據組件的props和state(無論兩者的重傳遞和重賦值。
論值是否有變化,都可以引起組件重新render),return一個React元素 (描述組件,即UI),不負責組件實際渲染工作。
之後由React自身根據此元素去渲染出頁面DOM。
render是純函數(函數的返回結果只依賴它的參數;
函數執行過程裡面沒有副作用),不能在裡面執行this.setState,會有改變組件狀態的副作用。
componentDidMount: 組件掛載到DOM後調用,且只會被調用一次。
在講述此階段前需要先明確下react組件更新機制。
setState引起的state更新或父組件更新render引起的props更新。
更新後的state和props相對之前無論是否有變化,都將引起組件的重新渲染。
父組件重新render 父組件重新render引起子組件重新render的情況有兩種:
a. 直接使用,每當父組件重新render導致的重傳props,子組件將直接跟著重新渲染。
無論props是否有變化,可通過shouldCo-mponentUpdate方法優化。
b.在componentWillReceiveProps方法中,將props轉換成自己的state
在該函數(componentWillReceiveProps)中調用 this.setState() 將不會引起第二次渲染。
是因為componentWillReceiveProps中判斷props是否變化了。
若變化了,this.setState將引起state變化,從而引起render,此時就沒必要再做第二次因重傳props引起的render了,不然重複做一樣的渲染了。
2.組件本身調用setState,無論state有沒有變化。
可通過shouldComponentUpdate方法優化。
此階段分為:
componentWillReceiveProps,shouldComponentUpdate;
componentWillUpdate,render,compo-nentDidUpdate;
componentWillReceiveProps(nextProps)
此方法只調用於props引起的組件更新過程中,參數nextProps是父組件傳給當前組件的新props。
但父組件render方法的調用不能保證重傳給當前組件的props是有變化的。
所以在此方法中根據nextProps和this.props來查明重傳的props是否改變,以及如果改變了要執行啥。
比如根據新的props調用this.setState出發當前組件的重新render
shouldComponentUpdate(nextProps, nextState)
此方法通過比較nextProps,nextState及當前組件的this.props,this.state。
返回true時當前組件將繼續執行更新過程,返回false則當前組件更新停止,以此可用來減少組件的不必要渲染,優化組件性能。
ps:這邊也可以看出,就算componentWi-llReceiveProps()中執行了this.setState,更新了state。
但在render前(如shouldComponentUpda-te,componentWillUpdate),this.state依然指向更新前的state,不然nextState及當前組件的this.state的對比就一直是true了。
componentWillUpdate(nextProps, nextState)
此方法在調用render方法前執行,在這邊可執行一些組件更新發生前的工作,一般較少用。
render
render方法在上文講過,這邊只是重新調用。
componentDidUpdate(prevProps, pre-vState)
此方法在組件更新後被調用。
可以操作組件更新的DOM,prevProps和prevState這兩個參數指的是組件更新前的props和state
此方法在組件被卸載前調用,可以在這裡執行一些清理工作。
比如清楚組件中使用的定時器,清楚componentDidMount中手動創建的DOM元素等,以避免引起內存洩漏。
使用React構建的單頁面應用,要想實現頁面間的跳轉,首先想到的就是使用路由。
在React中,常用的有兩個包可以實現這個需求,那就是react-router和react-router-dom。
react-router-dom
首先進入項目目錄,使用npm安裝react-router-dom:
npm install react-router-dom --save-dev //這裡可以使用cnpm代替npm命令
然後我們新建兩個頁面,分別命名為「home」和「detail」。在頁面中編寫如下代碼:
如上代碼定義了一個純路由組件,將兩個頁面組件Home和Detail使用Route組件包裹;
外面套用Switch作路由匹配,當路由組件檢測到地址欄與Route的path匹配時,就會自動加載響應的頁面。
然後在入口文件中——我這裡指定的是index.js——編寫如下代碼:
這裡相當於向頁面返回了一個路由組件。我們先運行項目看一下效果,在地址欄:
輸入http://localhost:3000/#/
輸入http://localhost:3000/#/detail
通過a標籤跳轉 可以看到其實路由已經開始工作了,接下來我們再來做頁面間的跳轉。
在home.js和detail.js中,我們修改如下代碼:
重新打包運行,在瀏覽器地址欄輸入「http://localhost:3000/」
試試看頁面能否正常跳轉。
如果不能,請按步驟一步一步檢查代碼是否有誤。
以上是使用a標籤的href進行頁面間跳轉,此外react-router-dom還提供了通過函數的方式跳轉頁面。
通過函數跳轉
首先我們需要修改router.js中的兩處代碼:
import {HashRouter, Route, Switch, hashHistory} from 'react-router-dom';
然後在home.js中:import React from 'react';
在a標籤下面添加一個按鈕並加上onClick事件。
通過this.props.history.push這個函數跳轉到detail頁面。
在路由組件中加入的代碼就是將history這個對象註冊到組件的props中去。
然後就可以在子組件中通過props調用history的push方法跳轉頁面。
很多場景下,我們還需要在頁面跳轉的同時傳遞參數。
在react-router-dom中,同樣提供了兩種方式進行傳參。
在router.js中,修改如下代碼:
然後修改detail.js,使用:
this.props.match.params獲取url傳過來的參數。
在地址欄輸入:
http://localhost:3000/#/detail/3
打開控制臺:
可以看到傳過去的id=3已經被獲取到了。react-router-dom就是通過「/:」去匹配url傳遞的參數。
隱式傳參 此外還可以通過push函數隱式傳參。修改home.js代碼如下:
在detail.js中,就可以使用this.props.history.location.state獲取home傳過來的參數:
replace 有些場景下,重複使用push或a標籤跳轉會產生死循環。
為了避免這種情況出現,react-router-dom提供了replace。
在可能會出現死循環的地方使用replace來跳轉:
this.props.history.replace('/detail');
this.props.history.goBack();
然後將它們添加進路由router.js,並且關聯父子關係:
react-router和react-router-dom的區別
先簡單說下各自的功能:
react-router:
實現了路由的核心功能 react-router-dom: 基於react-router,加入了在瀏覽器運行環境下的一些功能。
例如:Link組件,會渲染一個a標籤,Link組件源碼a標籤行; BrowserRouter和HashRouter組件。
前者使用pushState和popState事件構建路由,後者使用window.location.hash和hashchange事件構建路由。
react-router-native: 基於react-router,類似react-router-dom,加入了react-native運行環境下的一些功能。
react-router-dom依賴react-router,所以我們使用npm安裝依賴的時候,只需要安裝相應環境下的庫即可。
不用再顯式安裝react-router。
基於瀏覽器環境的開發,只需要安裝react-router-dom;
基於react-native環境的開發,只需要安裝react-router-native。
npm會自動解析react-router-dom包中package.json的依賴並安裝。
react-router-dom中package.json依賴:
安裝了react-router-dom,npm會解析並安裝上述依賴包。
可以看到,其中包括react-router。
所以,回到最開始的寫法。基於瀏覽器環境的開發,寫法1就可以了。
Route組件
Route組件用於組件的顯示,Route組件上有path和component屬性。
對應的path會顯示對應的component,路徑和組件產生對應的映射關係。
component屬性:
component能夠接受一個組件名,也可以接受一個函數
路由匹配的方式:
要路徑開頭匹配成功即會顯示對應的組件,就是當訪問/page1路徑的時候會匹配 / 的路徑 ,解決辦法是 exact屬性。
exact:
作用是嚴格匹配,路徑是什麼就匹配什麼,避免路徑匹配不正確的問題
Link組件和NavLink組件:
Link 組件是react-router中提供的路由切換的組件。
基於它可以實現點擊的時候實現路由的切換
to:'/xxx?xxx=123' 跳轉到指定的路由地址
to:
{pathname:'/xxx',search:'xxx:123',state:''}//可以基於state的方式傳參。
replace 默認值false 是替換HISTORY stack中當前的地址(true) 還是追加一個新的地址 (默認是追加)
基於link組件渲染,渲染後的結果是一個A標籤,to對應的信息最後會變成href的內容。
NavLink組件:
NavLink組件和LINK類似。
不同在於,NavLink組件在當前頁面地址和組件對應地址相吻合的時候,會默認給組件加一個active樣式,讓其有選中態(可以修改選中狀態)
activeClassName:
把默認你加的active樣式類改為自己設定的(默認是active)
activeStyle:
給匹配的NavLink設置行內樣式
exact 控制匹配的時候是否嚴格匹配(和route的一樣)
isActive:
()=>{} 匹配成功後執行對應函數(相當於路由的鉤子函數)
路由對象中的 history、location、 match、params
let {location:{pathname,search,sta-te}}=this.props;
pathname當前的hash路由地址
search查詢字符串
state 基於 redirect、link、nav-link中的to={},傳遞的是一個對象,對象中編寫的state,就可以通過 loactuion.state獲取。
3.match 匹配動態路由的值主要使用 params動態路由參數
let {match:{params}}=this.props;
console.log(params.id)//獲取的是動態路由匹配的一些結果,可用於動態傳參
Switch組件,用於嵌套Route組件
和switch case一樣,只能 選擇一個,避免一個路徑匹配多個組件。
像這種情況,可能都會被渲染到頁面上,此時Switch組件就有用了。
路由數據傳輸方式
不推薦:
本地存儲 localstroage
redux存儲 (頁面刷新數據就沒了) 點擊列表中某一項的時候,把信息存儲到本地或者redux中;
跳轉到詳情頁面,把信息從本地或者redux中獲取即可。
2.state傳值(一旦頁面刷新state傳的值就沒了)