【学习笔记】React+React全家桶学习笔记
文章目錄
- 1 為什么要使用React
- 2 React的定義
- 3 React的三大特性
- 4 React入門
- 4.1 hello_react
- 4.2 虛擬DOM的創建
- 4.3 JSX
- 4.4 模塊與組件,模塊化與組件化的理解
- 5 React面向組件編程
- 5.1 基本理解和使用
- 5.2 組件實例的三大核心屬性
- 5.2.1 state
- 5.2.2 props
- 5.2.3 ref
- 5.3 React中的事件處理
- 5.4 React中收集表單數據
- 5.4.1 非受控組件與非受控組件
- 5.5 組件的 生命周期
- 5.5.1 效果
- 5.5.2. 掛載與卸載
- 5.5.3 理解
- 5.5.4 生命周期流程圖(舊)
- 5.5.5 生命周期流程圖(新)
- 5.5.6 重要勾子和即將廢棄的勾子
- 5.6 虛擬DOM與DOM Diffing算法
- 6 React應用(基于React腳手架)
- 6.1 使用create-react-app創建react應用
- 6.1.1 react腳手架
- 6.1.2 創建項目并啟動
- 6.1.3 react腳手架項目結構
- 6.1.4 功能界面的組件化編碼流程(通用)
- 6.2 react ajax
- 6.2.1 理解
- 6.2.2 axios
- 6.2.3 react腳手架配置代理總結
- 6.2.4 消息訂閱-發布機制
- 6.2.5 擴展:Fetch(關注分離思想)
- 7 React路由
- 7.1 相關理解
- 7.1.1 SPA 的理解
- 7.1.2 路由的理解
- 7.1 .3 react-router-dom的理解
- 7.2 react-router-dom相關API
- 7.2.1 內置組件
- 7.2.2. 其它
- 8 代碼
- 9 參考
1 為什么要使用React
- 原生的JavaScript操作DOM繁瑣,效率低(DOM-API操作UI)
- 使用JavaScript,包括jQuery直接操作DOM,瀏覽器會進行大量的重繪和重排(雖然jQuery簡化了操作DOM的步驟,但依然效率低下)
- 原生的JavaScript沒有組件化編碼方案,代碼復用率低
2 React的定義
React的定義:用于構建用戶界面的JavaScript庫。
關鍵字:
換句話來說,React所做的有三步
也就是說React也可以定義為一個將數據渲染為HTML視圖的開源JavaScript庫。
3 React的三大特性
命令式編程 VS 聲明式編程:
簡單來說,命令式編程就是通過代碼來告訴計算機去做什么。
而聲明式編程是通過代碼來告訴計算機你想要做什么,讓計算機想出如何去做。
舉個生活中的例子就是:
命令式編程:我想喝一個冰可樂,然后我就會對身邊的XXX說:“XXX,你去廚房,打開冰箱,拿出一瓶冰可樂,打開之后送過來給我。”
聲明式編程:我想喝一個冰可樂,然后我就會對身邊的XXX說:“XXX,我想喝冰可樂。”而具體他是怎么拿到的冰可樂,怎么送過來的,是下樓買的還是在冰箱里拿的,我并不關心,我只關心我喝冰可樂的需求是否得到了滿足。
用代碼來舉個例子:
如果我要在界面上展示一個按鈕,并且點擊按鈕后會改變該按鈕的class。
用DOM編程寫的代碼就是命令式編程:首先你要指揮瀏覽器,第一步先要找到id為container的節點,然后創建一個button element,接著給這個button添加一個class name,然后添加一個點擊事件,最后將button添加到container節點里。這整個過程每一步操作都是命令式的,一步一步告訴瀏覽器要做什么。
而要實現相同功能,采用聲明式編程的React就簡單得多了。
首先我們定義一個Button組件,在render函數里通過返回一個類似HTML的數據結構,告訴React我要渲染一個Button,它是id為container的子節點。Button上的ClassName是動態變化的,當點擊按鈕時class要改變,這樣就可以了。至于render什么時候被執行,是如何渲染到頁面上的,點擊按鈕之后classname是如何更新的,這些都不需要你關心,你只需要告訴React你希望當前的UI應該是一個什么樣的狀態就可以了。
組件化的出現大幅度地提升了代碼地復用率,同時也改變了前端開發人員的一個編程思維
React的靈活性是由于它自身的定位決定的。React是一個用于構建用戶界面的JS庫,對于React來說,這里的用戶界面是一個抽象的虛擬的用戶界面,其實就是一個描述頁面狀態的數據結構。web頁面,移動客戶端頁面,VR界面都是用戶界面,只要配合相應的渲染器就能在不同的平臺中展示正確的UI界面。
通俗來說,我們可以把React的執行結果想象成一個視頻文件數據,在不同的播放器設備,我們通過轉換器將視頻編譯成不同的格式來讓他們在不同的播放器上正常地播放。所以在寫web端React時我們要額外引入React DOM來做渲染。
此外,React使用虛擬DOM+優秀的Diffing算法,盡量減少與真實DOM的交互,最小化頁面重繪
4 React入門
4.1 hello_react
4.2 虛擬DOM的創建
創建虛擬DOM的兩種方式
- 純JS方式(一般不用,過于繁瑣)
- JSX方式(簡單方便,最終由babel翻譯成js的形式,與用js寫的結果一樣)
虛擬DOM和真實DOM
-
React提供一些API來創建一種“特別”的一般js對象
const VDOM = React.createElement('xx',{id:'xx'},'xx')///依次為標簽名,標簽屬性和標簽內容上面創建的就是一個簡單的虛擬DOM對象
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-nCawKD9t-1624953908993)(https://i.loli.net/2021/04/25/qwd6egtIJMapLmA.png)]
-
我們編碼時基本只需要操作react的虛擬DOM相關數據,react就會轉換為真實的DOM
關于虛擬DOM總結:
4.3 JSX
鏈接:JSX基本語法規則
全稱: JavaScript XML
react定義的一種類似于XML的JS擴展語法: JS + XML,本質上還是JavaScript
是**React.createElement(component, props, …children)**方法的語法糖
作用:用來簡化創建虛擬DOM
- 寫法:var ele =
Hello JSX!
- 它不是字符串(不要加引號),也不是HTML/XML標簽
- 它最終產生的就是一個js對象
標簽名任意:HTML標簽或其他標簽
標簽屬性隨意:HTML標簽屬性或其它
基本語法規則
-
標簽首字母
? (1)若小寫字母開頭,則將該標簽轉為HTML中同名元素,若HTML中無該標簽對應的同名元素,則報錯。
? (2)若大寫字母開頭,則react就去渲染對用的組件,若組件沒有定義,則報錯
-
標簽中的js表達式必須用{ }包含
一定要區分:【JS語句(代碼)】與【js表達式】
-
表達式:一個表達式會產生一個值,可以放在任何一個需要值的地方
下面這些都是表達式:
- a
- a+b
- demo(1) //函數調用表達式
- arr.map()
- function test() { }
-
語句(代碼):不產生值
? 下面這些都是語句(代碼):
- if(){}
- for(){}
- switch(){case:xxx}
-
注釋需要寫在花括號{}中
-
樣式的類名指定不要寫class,要寫className
-
內聯樣式要用style={{key:value}}的形式寫第一個{}表示里面是一個js表達式,第二個{}表示里面是一個鍵值對,里面要寫小駝峰的形式, 比如font-size要寫成fontSize
<span style={{color:’#e0e0e0’, fontSize:18} }> myData
-
虛擬DOM只能有一個根標簽,有多個標簽時,可用一個div包起來
-
標簽必須閉合
- 瀏覽器不能直接解析JSX代碼, 需要babel轉譯為純JS的代碼才能運行
- 只要用了JSX,都要加上type=“text/babel”, 聲明需要babel來處理
4.4 模塊與組件,模塊化與組件化的理解
- 理解:向外提供特定功能的js程序,一般就是一個js文件
- 為什么要拆成模塊:因為隨著業務邏輯增加,代碼越來越多且復雜
- 作用:服用js,簡化js的編寫,提高js運行效率
- 理解:用來實現局部功能的代碼和資源的集合(html/css/js/image等等)
- 為什么一個界面的功能很復雜,不可能寫成一整塊,要分成一塊塊寫,然后拼起來
- 作用:復用編碼,簡化項目編碼,提高運行效率
當一個應用的js都是以模塊來編寫,這個應用就是一個模塊化的應用
當應用是以多組件的方式實現,這個應用就是一個組件化的應用
5 React面向組件編程
5.1 基本理解和使用
組件的類型
? 注意:
? (1)組件名必須首字母大寫
? (2)虛擬DOM元素只能有一個根元素
? (3)虛擬DOM元素必須有結束標簽
簡單組件:無狀態的組件
復雜組件:有狀態(state)的組件
狀態:舉例子說
- 人是有狀態的,比如今天的精神如何,人的狀態會影響人的行為
- 組件也是有狀態的,組件的狀態驅動頁面,數據放在狀態里
5.2 組件實例的三大核心屬性
5.2.1 state
- state是組件對象最重要的屬性, 值是==對象(==可以包含多個key-value的組合),用{}包裹
- 組件被稱為"狀態機", 通過更新組件的state來更新對應的頁面顯示(重新渲染組件)
- 組件中render方法中的this為組件實例對象
- 組件自定義的方法中this為undefined(作為事件的回調使用),如何解決?
- a) 強制綁定this: 通過函數對象的bind()
- b) 箭頭函數【要寫成賦值語句+箭頭函數的形式,類里面不支持function(){ }這種形式】
- 狀態數據,不能直接修改或更新,要用setState
5.2.2 props
- 每個組件對象都會有props(properties的簡寫)屬性
- 組件標簽的所有屬性都保存在props中
- 通過標簽屬性從組件外向組件內傳遞變化的數據
- 注意: 組件內部不要修改props數據
-
內部讀取某個屬性值: this.props.name
-
對props中的屬性值進行類型限制和必要性限制
-
第一種方式(React v15.5 開始已棄用):
Person.propTypes = {name: React.PropTypes.string.isRequired,age: React.PropTypes.number } -
第二種方式(新):使用prop-types庫進限制(需要引入prop-types庫)
Person.propTypes = {name: PropTypes.string.isRequired,age: PropTypes.number. } -
擴展屬性:將對象的所有屬性通過props傳遞:<Person {…person}/>
-
默認屬性值:
-
組件類的構造函數
constructor(props){super(props)console.log(props)//打印所有屬性 }
5.2.3 ref
理解:組件內的標簽可以定義ref屬性來標識自己
編碼
-
字符串形式的ref:(已經不被react推薦使用)官方說明
<input ref = 'input1'/> -
回調形式的ref
<input ref={(c)=>{this.input1 = c}} -
createRef創建ref容器
5.3 React中的事件處理
通過onXxx屬性指定處理函數(注意大小寫,與原生的js區分開)
? a) React使用的是自定義(合成)事件, 而不是使用的原生DOM事件 ——目的是為了更好的兼容性
? b) React中的事件是通過事件委托方式處理的(委托給組件最外層的元素) ——目的是為了高效
通過event.target得到發生事件的DOM元素對象 ——為了避免過度使用ref
不要過度使用ref,當發生事件的DOM正好是要操作的DOM元素時可以用event.target的形式
5.4 React中收集表單數據
5.4.1 非受控組件與非受控組件
非受控組件:現用現取(ref)
受控組件:隨著輸入維護狀態為受控組件(onChange , setState)
5.5 組件的 生命周期
5.5.1 效果
需求:定義組件實現以下功能:
5.5.2. 掛載與卸載
掛載:mount。當 組件第一次被渲染到 DOM 中的時候,就為其設置一個計時器。這在 React 中被稱為“掛載(mount)”。
卸載:unmount。同時,當 DOM 中 組件被刪除的時候,應該清除計時器。這在 React 中被稱為“卸載(unmount)”
5.5.3 理解
5.5.4 生命周期流程圖(舊)
生命周期的三個階段(舊)
初始化階段: 由ReactDOM.render()觸發—初次渲染
? 1). constructor()
? 2). componentWillMount()
? 3). render()
? 4). componentDidMount() = = = =>常用,一般在這個鉤子中做一些初始化的事,例如開啟定時器、 發送網絡請求、訂閱消息、開啟監聽, 發送ajax請求等
更新階段: 由組件內部this.setSate()或父組件重新render觸發
? 1). shouldComponentUpdate()
? 2). componentWillUpdate()
? 3). render() = = = =>必須要使用
? 4). componentDidUpdate()
卸載組件: 由ReactDOM.unmountComponentAtNode()觸發
? 1). componentWillUnmount() = = = =>常用,一般在這個鉤子做一些收尾的工作,例如,關閉定時 器、取消訂閱消息
5.5.5 生命周期流程圖(新)
生命周期的三個階段(新)
**1. ** 初始化階段: 由ReactDOM.render()觸發—初次渲染
? constructor()
getDerivedStateFromProps(新增,很少用,上官網了解即可)
? (此方法適用于罕見的用例,即 state 的值在任何時候都取決于 props)
? render()
? componentDidMount()
更新階段: 由組件內部this.setSate()或父組件重新render觸發
? getDerivedStateFromProps
? shouldComponentUpdate()
render()**getSnapshotBeforeUpdate ** 在更新之前獲取快照,有點實用意義
componentDidUpdate()**3. ** 卸載組件: 由ReactDOM.unmountComponentAtNode()觸發
? componentWillUnmount()
5.5.6 重要勾子和即將廢棄的勾子
- render:必須要使用,初始化渲染或更新渲染調用
- componentDidMount:一般在這個鉤子中做一些初始化的事,例如開啟定時器、 發送網絡請求、訂閱消息,開啟監聽, 發送ajax請求等
- componentWillUnmount:做一些收尾工作, 如: 清理定時器,取消訂閱等
- componentWillMount
- componentWillReceiveProps
- componentWillUpdate
16版本能正常使用,17版本使用會出現警告,下一個大版本需要加上UNSAFE_前綴才能使用,以后可能會被徹底廢棄,不建議使用。
5.6 虛擬DOM與DOM Diffing算法
經典面試題:
1). react/vue中的key有什么作用?(key的內部原理是什么?)
2). 為什么遍歷列表時,key最好不要用index?
虛擬DOM中key的作用:
1). 簡單地說: key是虛擬DOM對象的標識, 在更新顯示時key起著極其重要的作用。
2). 詳細地·說: 當狀態中的數據發生變化時,react會根據【新數據】生成【新的虛擬DOM】, 隨后React進行【新虛擬DOM】與【舊虛擬DOM】的diff比較,比較規則如下:
? a. 舊虛擬DOM中找到了與新虛擬DOM相同的key:
? (1).若虛擬DOM中內容沒變, 直接使用之前的真實DOM
? (2).若虛擬DOM中內容變了, 則生成新的真實DOM,隨后替換掉頁面中之前的真實DOM
? b. 舊虛擬DOM中未找到與新虛擬DOM相同的key
? 根據數據創建新的真實DOM,隨后渲染到到頁面
? 1) 若對數據進行:逆序添加、逆序刪除等破壞順序操作:
? 會產生沒有必要的真實DOM更新 ==> 界面效果沒問題, 但效率低。
? 2.)如果結構中還包含輸入類的DOM:
? 會產生錯誤DOM更新 ==> 界面有問題。
? 3) ==注意!==如果不存在對數據的逆序添加、逆序刪除等破壞順序操作, 僅用于渲染列表用于展 示,使用index作為key是沒有問題的。
?
? 3. 開發中如何選擇key?:
? 1) 最好使用每條數據的唯一標識作為key, 比如id、手機號、身份證號、學號等唯一值。
? 2) 如果確定只是簡單的展示數據,用index也是可以的。
6 React應用(基于React腳手架)
6.1 使用create-react-app創建react應用
6.1.1 react腳手架
xxx腳手架: 用來幫助程序員快速創建一個基于xxx庫的模板項目
1)包含了所有需要的配置(語法檢查、jsx編譯、devServer…)
2) 下載好了所有相關的依賴、
3)可以直接運行一個簡單效果
react提供了一個用于創建react項目的腳手架庫: create-react-app
項目的整體技術架構為: react + webpack + es6 + eslint
使用腳手架開發的項目的特點: 模塊化, 組件化, 工程化
6.1.2 創建項目并啟動
第一步,全局安裝:npm i -g create-react-app
第二步,切換到想創項目的目錄,使用命令:create-react-app hello-react
第三步,進入項目文件夾:cd hello-react
第四步,啟動項目:npm start
6.1.3 react腳手架項目結構
public ---- 靜態資源文件夾
? favicon.icon ------ 網站頁簽圖標(一定要是icon格式)
? index.html -------- 主頁面(整個項目只有這一個html文件,SPA應用,即單頁面應用)
? logo192.png ------- logo圖
? logo512.png ------- logo圖
? manifest.json ----- 應用加殼的配置文件
? robots.txt -------- 爬蟲協議文件
src ---- 源碼文件夾
? App.css -------- App組件的樣式
? App.js --------- App 組件
? App.test.js ---- 用于給App做測試(幾乎不用)
? index.css ------ 樣式
? index.js ------- 入口文件
? logo.svg ------- logo圖
? reportWebVitals.js
? — 頁面性能分析文件(需要web-vitals庫的支持)
? setupTests.js
? ---- 組件單元測試的文件(需要jest-dom庫的支持)
6.1.4 功能界面的組件化編碼流程(通用)
拆分組件: 拆分界面,抽取組件
實現靜態組件: 使用組件實現靜態頁面效果
實現動態組件
? 3.1 動態顯示初始化數據
? 3.1.1 數據類型
? 3.1.2 數據名稱
? 3.1.3 保存在哪個組件?
? 3.2 交互(從綁定事件監聽開始)
6.2 react ajax
6.2.1 理解
-
React本身只關注于界面, 并不包含發送ajax請求的代碼
-
前端應用需要通過ajax請求與后臺進行交互(json數據)
-
react應用中需要集成第三方ajax庫(或自己封裝)
-
Query: 比較重, 如果需要另外引入不建議使用
-
axios: 輕量級, 建議使用
? 1) 封裝XmlHttpRequest對象的ajax
? 2) promise風格
? 3) 可以用在瀏覽器端和node服務器端
6.2.2 axios
-
GET請求
axios.get('/user?ID=12345').then(function (response) {console.log(response.data);}).catch(function (error) {console.log(error);});axios.get('/user', {params: {ID: 12345}}).then(function (response) {console.log(response);}).catch(function (error) {console.log(error);}); -
POST請求
axios.post('/user', {firstName: 'Fred',lastName: 'Flintstone' }) .then(function (response) { console.log(response); }) .catch(function (error) { console.log(error); });
6.2.3 react腳手架配置代理總結
方法1
? 在package.json中追加如下配置
"proxy":"http://localhost:5000"? 說明:
? 1)優點:配置簡單,前端請求資源時可以不加任何前綴。
? 2)缺點:不能配置多個代理。
? 3)工作方式:上述方式配置代理,當請求了3000不存在的資源時,那么該請求會轉發給5000 (優先匹配前端資源)
方法2:
? 1)第一步:創建代理配置文件
? 在src下創建配置文件:src/setupProxy.js
? 2) 編寫setupProxy.js配置具體代理規則:
const proxy = require('http-proxy-middleware')module.exports = function(app) {app.use(proxy('/api1', { //api1是需要轉發的請求(所有帶有/api1前綴的請求都會轉發給5000)target: 'http://localhost:5000', //配置轉發目標地址(能返回數據的服務器地址)changeOrigin: true, //控制服務器接收到的請求頭中host字段的值/*changeOrigin設置為true時,服務器收到的請求頭中的host為:localhost:5000changeOrigin設置為false時,服務器收到的請求頭中的host為:localhost:3000changeOrigin默認值為false,但我們一般將changeOrigin值設為true*/pathRewrite: {'^/api1': ''} //去除請求前綴,保證交給后臺服務器的是正常請求地址(必須配置)}),proxy('/api2', { target: 'http://localhost:5001',changeOrigin: true,pathRewrite: {'^/api2': ''}}))}? 說明:
6.2.4 消息訂閱-發布機制
工具庫: PubSubJS
下載: npm install pubsub-js --save
使用:
? 1) import PubSub from ‘pubsub-js’ //引入
? 2) PubSub.subscribe(‘delete’, function(data){ }); //訂閱
? 3) PubSub.publish(‘delete’, data) //發布消息
理解
? 1)先訂閱,再發布(理解:有一種隔空對話的感覺)
? 2)適用于任意組件間通信
? 3)要在組件的componentWillUnmount中取消訂閱
6.2.5 擴展:Fetch(關注分離思想)
文檔
1) https://github.github.io/fetch/
2) https://segmentfault.com/a/1190000003810652
特點
1)fetch: 原生函數,不再使用XmlHttpRequest對象提交ajax請求(axios和jQuery都是對XmlHttpRequset的封裝)
2)老版本瀏覽器可能不支持
相關API
1)GET請求
fetch(url).then(function(response) {return response.json()}).then(function(data) {console.log(data)}).catch(function(e) {console.log(e)});2)POST請求
fetch(url, {method: "POST",body: JSON.stringify(data),}).then(function(data) {console.log(data)}).catch(function(e) {console.log(e)})7 React路由
7.1 相關理解
7.1.1 SPA 的理解
單頁Web應用(single page web application,SPA)。
整個應用只有==一個完整的頁面==。
點擊頁面中的鏈接==不會刷新頁面,只會做頁面的局部更新。==
數據都需要通過ajax請求獲取, 并在前端異步展現。
7.1.2 路由的理解
1. 什么是路由?
-
一個路由就是一個映射關系(key:value)
-
key為路徑, value可能是function或component
2. 路由分類
? 1) 后端路由:
-
理解: value是function, 用來處理客戶端提交的請求。
-
注冊路由: router.get(path, function(req, res))
-
工作過程:當node接收到一個請求時, 根據請求路徑找到匹配的路由, 調用路由中的函數來處理請求, 返回響應數據
? 2) 前端路由:
-
瀏覽器端路由,value是component,用于展示頁面內容。
-
注冊路由:
-
工作過程:當瀏覽器的path變為/test時, 當前路由組件就會變為Test組件
7.1 .3 react-router-dom的理解
react的一個插件庫。
專門用來實現一個SPA應用。
基于react的項目基本都會用到此庫。
7.2 react-router-dom相關API
7.2.1 內置組件
< BrowserRouter >
< HashRouter >
< Route >
< Redirect >
< Link >
< NavLink >
< Switch >
7.2.2. 其它
history對象
match對象
withRouter函數
8 代碼
里面由筆記的markdown版本和源代碼,還有一些其他的學習筆記
GitHub地址
9 參考
尚硅谷React全家桶
ps:張天禹老師講得超級棒,yysd
總結
以上是生活随笔為你收集整理的【学习笔记】React+React全家桶学习笔记的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Debian字体美化
- 下一篇: 树上战争(2545)