前端必備:React的生命周期和路由

2021-02-19 開課吧前端團隊

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傳的值就沒了)

相關焦點

  • 每個前端開發必看的React生命周期函數
    要達到這樣的目標學習React最基本的生命周期函數對編寫高性能、可復用組件會有很大的幫助。在初始化階段有4個生命周期函數:getDefaultProps()是可以設置組件的默認屬性值;componentWillMount()是組件初始化時調用,在整個生命周期中只調用一次;
  • 前端路由的實現
    之前面試,面試官問了我一個前端路由與後端路由的問題其實我之前在上線自己的博客遇到過下面這些問題為啥我寫的Vue應用在開發階段都沒問題,部署到服務端之後訪問不了除了/的頁面呢為啥我寫的SPA頁面的路由用hash模式都沒問題,改成history模式就問題百出呢啥是前端路由啥是後端路由,要怎麼配後端才能支持我的前端路由呢什麼是路由理解
  • React V16.3 即將更改的生命周期
    我們了解到的最大問題之一是,我們的一些傳統組件生命周期會導致一些不安全的編碼實踐。他們是:這些生命周期方法經常被誤解和濫用;此外,我們預計他們的潛在濫用可能在異步渲染方面有更大的問題。因此,我們將在即將發布的版本中為這些生命周期添加一個「UNSAFE_」前綴。
  • 第285天:React生命周期
    React生命周期React的生命周期從廣義上分為掛載、渲染、卸載三個階段,在React的整個生命周期中提供很多鉤子函數在生命周期的不同時刻調用
  • Java學習進階之React狀態保存
    但是在React中並沒有這個功能,前端人員又該如何實現狀態保存呢?接下來千鋒廣州HTML5大前端培訓小編就給大家分享常用的幾個方法。1、手動保存狀態手動保存狀態,是比較常見的解決方式,可以配合React組件的componentWillUnmount生命周期,通過redux之類的狀態管理層對數據進行保存,通過componentDidMount周期進行數據恢復。
  • 我對 React V16.4 生命周期的理解
    React 為三個生命周期函數加上了 UNSAFE 前綴,並明確表示會在 V17.0 版本中刪除這三個生命周期函數。主要是這些生命周期方法經常被誤用和濫用。並且在 React V16.0 之前,React 是同步渲染的,而在 V16.0 之後 React 更新了其渲染機制,是通過異步的方式進行渲染的,在 render 函數之前的所有函數都有可能被執行多次。
  • React SSR 同構入門與原理
    同構思路CSR 客戶端渲染CSR 客戶端渲染,這個就是很好理解了,使用 React , React Router 前端自己控制路由的 SPA 項目,就可以理解成客戶端渲染。它有一個非常大的優勢就是,只是首次訪問會請求後臺服務加載相應文件,之後的訪問都是前端自己判斷 URL 展示相關組件,因此除了首次訪問速度慢些之外,之後的訪問速度都很快。執行命令: create-react-app react-csr 創建一個 React SPA 單頁面應用項目 。執行命令: npm run start 啟動項目。
  • 【前端技術】react渲染 - 流程概述
    作者:winkchen  騰訊IEG前端開發工程師|導語 web前端技術中
  • 前端技術:React&Vue對比
    React和vue的業務邏輯是差不多,vue在react上封裝了更簡潔的方法,使用起來更加的便捷,如:提供了便捷的指令(v-for,v-if,v-model),還提供了更多的屬性(computed,watch),我還是比較喜歡用react的,更接近js原生,更容易於理解它。
  • react的核心api-前端進階
    React V16.3 之前的生命周期 image-20190111173300397 範例:驗證生命周期,創建 Lifecycle.js import React, { Component } from "react";
  • react腳手架create-react-app入門
    記得關注,每天都在分享不同知識不管是哪個前端框架都支持快速開發,通過腳手架可以讓咱們更便捷的構建項目,無需考慮搭建環境問題,今天來聊聊create-react-app腳手架安裝腳手架>npm install -g create-react-app創建項目create-react-app myapp # myapp是項目的名稱,這樣就會在當前目錄生成一個myapp的項目
  • React 生態系統:從小白到大神
    一言以蔽之,ReactJS 解決了前端技術規劃中應該考慮的這幾件事:組件化、模塊化、開發效率、運行效率、可維護性…1.2 React生命周期下圖很直觀地描述了 React 生命周期的整個過程:React生命周期這裡有個不錯的 github 項目:react-pxq。
  • 你好,談談你對前端路由的理解
    1、為什麼會出現前端路由。2、前端路由解決了什麼問題。3、前端路由實現的原理是什麼。這就達到了無刷新頁面切換的效果,從側面也能說明正因為無刷新,所以 React 、 Vue 、 Angular 等現代框架在創建頁面組件的時候,每個組件都有自己的 生命周期 。
  • 「源碼解析 」這一次徹底弄懂react-router路由原理
    筆者個人感覺學習react-router,有助於我們學習單頁面應用(spa)路由跳轉原理,讓我們理解從history.push,到組件頁面切換的全套流程,使我們在面試的時候不再為路由相關的問題發怵,廢話不說,讓我們開啟深入react-router源碼之旅吧。一 正確理解react-router1 理解單頁面應用什麼是單頁面應用?
  • 前端面試題集合
    bind,apply,call的區別以及bind的實現算法:反轉二叉樹以及時間複雜度鍊表找環react的virtual DOM和Diff算法React的生命周期Vue的生命周期boostrap的底層原理圖片壓縮的原理如何處理高並發的情況下,用戶順序問題說一下web安全,xss
  • webpack4+react16+react-router-dom4從零配置到優化,實現路由按需...
    上一篇介紹了下webpack的一些配置,接下來講下reactRouter4裡面關於路由的一些配置,如何做到模塊的按需加載,這也是常用的一種優化網站性能的方式
  • 【翻譯】基於 Create React App路由4.0的異步組件加載(Code...
    當然這個操作不是完全必要的,但如果你好奇的話,請隨意跟隨這篇文章一起用Create React App和 react路由4.0的異步加載方式來幫助react.js構建大型應用。 代碼分割(Code Splitting) 當我們用react.js寫我們的單頁應用程式時候,這個應用會變得越來越大,一個應用(或者路由頁面)可能會引入大量的組件,可是有些組件是第一次加載的時候是不必要的,這些不必要的組件會浪費很多的加載時間。
  • 修復 React 代碼中煩人的 Warning
    render 函數之前的所有生命周期函數(包括 render)都屬於第一階段,之後的都屬於第二階段。在 React v16.3 之前,render 之前的生命周期函數(也就是第一階段生命周期函數)包括這些:componentWillReceiveProps上面提到的濫用,其實就是在這些生命周期中產生了副作用,這些生命周期都應該是純函數,不應該產生任何副作用。
  • React系列教程
    view層的前端框架。所以,越來越多的人開始關注和使用,認為它可能是將來 Web 開發的主流工具。但是由於他的學習曲線較高,讓很多想學習前端的人員望而卻步,但是他的聲明式設計、高效、靈活的特點也讓它在前端有著一定的較高地位,也是前端人員必備的技能之一。本課程就讓我們從無到有,一點一滴的系統的學習React.JS,逐漸的成為一名React.JS的使用高手。
  • 為什麼我說你應該學React源碼?
    國內的前端領域,Vue 和 React 是最火的兩個框架,要說崗位數量,Vue可能會更多一點。