React18.x-學習筆記


react核心庫

  • react-development.js
  • react-dom-development.js
  • bebal.min.js

jsx語法規則

  • 定義虛擬Dom時,不要寫引號。
  • 標簽中混入js表達式要用{}。
  • 樣式的類名指定不要用class 要用className
  • 內聯樣式,要用style={對象}—> style={{key:value}}的形式去寫
  • 只能有一個根標簽
  • 標簽必須閉合或者單標簽自閉合
  • 標簽首字母
    1. 若小寫字母開頭,則將該標簽轉為html中同名元素,若HTML中無該標簽對應的同名元素,則報錯。
    2. 若大寫字母開頭,react就去渲染對應的組件,若組件沒有定義,則報錯。

靈魂拷問

  • 在復雜組件中 constructor構造函數執行幾次?
    答:有幾個復雜組件的實例就執行幾次,只有一個組件實例則執行一次
  • 在復雜組件中render函數執行幾次?
    答:當狀態發生改變時則重新執行render函數 1+n次。 1代表初始化時執行。n代表狀態(state)更新了幾次。

組件三大特性

1.狀態(state).
2.props.
3.ref

高階函數

定義:什么是高階函數?
如果一個函數符合下面2個規范中的任何一個,那該函數就是高階函數。

  • 若A函數,接受的參數是一個函數,那么A就可以稱之為高階函數。
  • 若A函數,調用的返回值依然是一個函數,那么A就可以稱之為高階函數。
    常見的高階函數有:Promise setTimeout arr.map() arr.reduce() arr.filter() arr.some() arr.sort() ….
    函數柯里化:通過函數調用繼續返回函數的方式,實現多次接受參數最后統一處理的函數編碼形式。

生命周期(重要)

在React17.0.0版本之前的生命周期鈎子(舊版本)
執行順序

  • constructor
  • componentDidMount 組件掛載前執行的鈎子
  • render 函數在中間執行
  • componentDidMount 組件掛載完成后執行的鈎子 //常用 比如:開啟定時器,發送網絡請求,訂閱消息
  • componentWillUnmount 組件卸載前執行的鈎子 //常用 比如:關閉定時器,取消訂閱消息
    更新組件執行的生命周期鈎子
  • shouldComponentUpdate 用於控制是否更新狀態的鈎子
    ​ 不寫默認返回true 在組件中寫入這個鈎子必須要返回值
  • componentWillUpdate 組件更新前的鈎子 即將廢除
  • render 函數執行
  • componentDidUpdate 組件更新完畢執行鈎子

新版本生命周期

  • 即將廢除3個生命周期鈎子 新增2個生命周期鈎子
    即將廢除:componentWillMount、componentWillReceiveProps 、componentWillUpdate
    這些鈎子都是不常用的鈎子
    新增鈎子:getDerivedStateFromProps
    ​ getSnapshotBeforeUpdate

虛擬DOM的Diffing算法

  • 在循環列表項中加入Key值利於提高Diff算法的效率
  • diff算法比較新舊dom 然后根據key來判斷舊的虛擬Dom節點是否可以復用。
  • 在循環列表項中如果要打亂順序插入列表項,不要使用數組的索引值(index)來作為key使用。這樣會發生嚴重后果且跟新效率低下。

訂閱消息與發布消息 pubsub-js

安裝訂閱發布消息庫 pubsub-js

  • yarn add pubsub-js
    在組件中引入pubsub庫
    import PubSub from 'pubsub-js'
  • 在組件中發布消息。
    PubSub.publish(‘發布的消息名稱’,payload(載荷/數據))
  • 在組件中訂閱消息,一般在組件掛載完成的時候訂閱,在componentDidMount鈎子中訂閱
    this.token = PubSub.subscribe(‘訂閱的消息名稱’,(mesName,data)=>{
    console.log(mesName,data)// 事件名稱,收到發布消息的載荷
    })
    
  • 在組件卸載前取消訂閱 componentWillUnmount鈎子中取消訂閱
    componentWillUnmount(){
     	PubSub.unsubscribe(this.token);
    }
    

react 路由

  • 核心庫:react-router-dom

  • 路由組件的使用

    import {withRouter,HashRouter,BrowserRouter,Link,NavLink,Switch,Redirect,Route} from 'react-router-dom'
    
  • 各組件的功能

    • HashRouter組件,使用Hash模式的路由器,(用的不多)
    • BrowserRouter組件,瀏覽器使用的路由器,使用history模式進行路由切換,一般在SPA應用上包裹在App組件上。
    • Link組件,進行路由導航鏈接的組件
    • NavLink組件,進行路由導航鏈接的組件 多一個高亮效果,默認active類名。
      • 可以通過activename來更改選中時的類名
    • Switch組件,Switch包裹在路由組件中 <Switch> <Route/></Switch>中.
      • 用於對路由匹配的限制,匹配到了就不往下匹配了。就終止路由匹配
    • Redirect組件,重定向組件。一般用來兜底的組件。
      • 在路由組件什么也沒匹配到的情況下,Redirect重定向到指定路徑中。
    • Route組件 路由組件
      • 將一般組件變成路由組件,同時可以指定匹配的路徑。路由組件中還會有this.props.history的API
    • withRouter 方法,
      • 將一般組件變成路由組件的函數,同時擁有historyAPI
      • 使用方式: withRouter(componentName)
      • 返回一個新組件,導出即可。
  • 路由的模糊匹配和嵌套路由。

    • 默認路由采用的是,模糊匹配。 如果想要嚴格匹配 加上 exact
    • 嵌套路由
      • 1.注冊子路由時要寫上父路由的path值
      • 2.路由的匹配是按照注冊路由的順序進行的
  • 路由傳遞參數(重要)

    		1.params參數
    					路由鏈接(攜帶參數):<Link to='/demo/test/tom/18'}>詳情</Link>
    					注冊路由(聲明接收):<Route path="/demo/test/:name/:age" component={Test}/>
    					接收參數:this.props.match.params
    		2.search參數
    					路由鏈接(攜帶參數):<Link to='/demo/test?name=tom&age=18'}>詳情</Link>
    					注冊路由(無需聲明,正常注冊即可):<Route path="/demo/test" component={Test}/>
    					接收參數:this.props.location.search
    					備注:獲取到的search是urlencoded編碼字符串,需要借助querystring解析
    		3.state參數
    					路由鏈接(攜帶參數):<Link to={{pathname:'/demo/test',state:{name:'tom',age:18}}}>詳情</Link>
    					注冊路由(無需聲明,正常注冊即可):<Route path="/demo/test" component={Test}/>
    					接收參數:this.props.location.state
    					備注:刷新也可以保留住參數
    

redux要點

1. redux理解
2. redux相關API
3. redux核心概念(3個)
4. redux工作流程
5. 使用redux及相關庫編碼

1. redux理解

什么?: redux是專門做狀態管理的獨立第3方庫, 不是react插件
作用?: 對應用中狀態進行集中式的管理(寫/讀)
開發: 與react-redux, redux-thunk等插件配合使用

2. redux相關API

redux中包含: createStore(), applyMiddleware(), combineReducers()
store對象: getState(), dispatch(), subscribe()
react-redux: <Provider>, connect()()

3. redux核心概念(3個)

action: 
	默認是對象(同步action), {type: 'xxx', data: value}, 需要通過對應的actionCreator產生, 
	它的值也可以是函數(異步action), 需要引入redux-thunk才可以
reducer
	根據老的state和指定的action, 返回一個新的state
	不能修改老的state
store
	redux最核心的管理對象
	內部管理着: state和reducer
	提供方法: getState(), dispatch(action), subscribe(listener)

4. redux工作流程


5. 使用redux及相關庫編碼

需要引入的庫: 
	redux
	react-redux
	redux-thunk
	redux-devtools-extension(這個只在開發時需要)
redux文件夾: 
	action-types.js
	actions.js
	reducers.js
	store.js
組件分2類: 
	ui組件(components): 不使用redux相關PAI
	容器組件(containers): 使用redux相關API

6.React-擴展

setState

setState更新狀態的2種寫法

	(1). setState(stateChange, [callback])------對象式的setState
            1.stateChange為狀態改變對象(該對象可以體現出狀態的更改)
            2.callback是可選的回調函數, 它在狀態更新完畢、界面也更新后(render調用后)才被調用
					
	(2). setState(updater, [callback])------函數式的setState
            1.updater為返回stateChange對象的函數。
            2.updater可以接收到state和props。
            4.callback是可選的回調函數, 它在狀態更新、界面也更新后(render調用后)才被調用。
總結:
		1.對象式的setState是函數式的setState的簡寫方式(語法糖)
		2.使用原則:
				(1).如果新狀態不依賴於原狀態 ===> 使用對象方式
				(2).如果新狀態依賴於原狀態 ===> 使用函數方式
				(3).如果需要在setState()執行后獲取最新的狀態數據, 要在第二個callback函數中讀取

setState()的異步與同步

1). setState()更新狀態是異步還是同步的?
    a. 執行setState()的位置?
        在react控制的回調函數中: 生命周期勾子 / react事件監聽回調
        非react控制的異步回調函數中: 定時器回調 / 原生事件監聽回調 / promise回調 /...
    b. 異步 OR 同步?
        react相關回調中: 異步
        其它異步回調中: 同步
2). 關於異步的setState()
    a. 多次調用, 如何處理?
        setState({}): 合並更新一次狀態, 只調用一次render()更新界面 ---狀態更新和界面更新都合並了
        setState(fn): 更新多次狀態, 但只調用一次render()更新界面  ---狀態更新沒有合並, 但界面更新合並了
    b. 如何得到異步更新后的狀態數據?
        在setState()的callback回調函數中

2. lazyLoad

路由組件的lazyLoad

	//1.通過React的lazy函數配合import()函數動態加載路由組件 ===> 路由組件代碼會被分開打包
	const Login = lazy(()=>import('@/pages/Login'))
	
	//2.通過<Suspense>指定在加載得到路由打包文件前顯示一個自定義loading界面
	<Suspense fallback={<h1>loading.....</h1>}>
        <Switch>
            <Route path="/xxx" component={Xxxx}/>
            <Redirect to="/login"/>
        </Switch>
    </Suspense>

3. Hooks

1. React Hook/Hooks是什么?

(1). Hook是React 16.8.0版本增加的新特性/新語法
(2). 可以讓你在函數組件中使用 state 以及其他的 React 特性

2. 三個常用的Hook

(1). State Hook: React.useState()
(2). Effect Hook: React.useEffect()
(3). Ref Hook: React.useRef()

3. State Hook

(1). State Hook讓函數組件也可以有state狀態, 並進行狀態數據的讀寫操作
(2). 語法: const [xxx, setXxx] = React.useState(initValue)  
(3). useState()說明:
        參數: 第一次初始化指定的值在內部作緩存
        返回值: 包含2個元素的數組, 第1個為內部當前狀態值, 第2個為更新狀態值的函數
(4). setXxx()2種寫法:
        setXxx(newValue): 參數為非函數值, 直接指定新的狀態值, 內部用其覆蓋原來的狀態值
        setXxx(value => newValue): 參數為函數, 接收原本的狀態值, 返回新的狀態值, 內部用其覆蓋原來的狀態值

4. Effect Hook

(1). Effect Hook 可以讓你在函數組件中執行副作用操作(用於模擬類組件中的生命周期鈎子)
(2). React中的副作用操作:
        發ajax請求數據獲取
        設置訂閱 / 啟動定時器
        手動更改真實DOM
(3). 語法和說明: 
        useEffect(() => { 
          // 在此可以執行任何帶副作用操作
          return () => { // 在組件卸載前執行
            // 在此做一些收尾工作, 比如清除定時器/取消訂閱等
          }
        }, [stateValue]) // 如果指定的是[], 回調函數只會在第一次render()后執行
    
(4). 可以把 useEffect Hook 看做如下三個函數的組合
        componentDidMount()
        componentDidUpdate()
    	componentWillUnmount() 

5. Ref Hook

(1). Ref Hook可以在函數組件中存儲/查找組件內的標簽或任意其它數據
(2). 語法: const refContainer = useRef()
(3). 作用:保存標簽對象,功能與React.createRef()一樣

4. Fragment使用

<Fragment><Fragment>
<></>

作用

可以不用必須有一個真實的DOM根標簽了


## 5. Context ### 理解 > 一種組件間通信方式, 常用於【祖組件】與【后代組件】間通信 ### 使用 ```js 1) 創建Context容器對象: const XxxContext = React.createContext()
  1. 渲染子組時,外面包裹xxxContext.Provider, 通過value屬性給后代組件傳遞數據:
    <xxxContext.Provider value={數據}>
    子組件
    </xxxContext.Provider>

  2. 后代組件讀取數據:
    //第一種方式:僅適用於類組件
    static contextType = xxxContext // 聲明接收context
    this.context // 讀取context中的value數據

    //第二種方式: 函數組件與類組件都可以
    <xxxContext.Consumer>
    {
    value => ( // value就是context中的value數據
    要顯示的內容
    )
    }
    </xxxContext.Consumer>

### 注意
	在應用開發中一般不用context, 一般都用它的封裝react插件
<hr/>
## 6. 組件優化 Component與PureComponent
```js
1). Component存在的問題?
    a. 父組件重新render(), 當前組件也會重新執行render(), 即使沒有任何變化
    b. 當前組件setState(), 重新執行render(), 即使state沒有任何變化
2). 解決Component存在的問題
    a. 原因: 組件的shouldcomponentUpdate()默認返回true, 即使數據沒有變化render()都會重新執行
    b. 辦法1: 重寫shouldComponentUpdate(), 判斷如果數據有變化返回true, 否則返回false
    c. 辦法2: 使用PureComponent代替Component
    d. 說明: 一般都使用PureComponent來優化組件性能
3). PureComponent的基本原理
    a. 重寫實現shouldComponentUpdate()
    b. 對組件的新/舊state和props中的數據進行淺比較, 如果都沒有變化, 返回false, 否則返回true
    c. 一旦componentShouldUpdate()返回false不再執行用於更新的render()
  
4). 面試題:
    組件的哪個生命周期勾子能實現組件優化?
    PureComponent的原理?
    區別Component與PureComponent?

## 7. render props ### 如何向組件內部動態傳入帶內容的結構(標簽)? Vue中: 使用slot技術, 也就是通過組件標簽體傳入結構 React中: 使用children props: 通過組件標簽體傳入結構 使用render props: 通過組件標簽屬性傳入結構,而且可以攜帶數據,一般用render函數屬性 ### children props xxxx {this.props.children} 問題: 如果B組件需要A組件內的數據, ==> 做不到 ### render props }> A組件: {this.props.render(內部state數據)} C組件: 讀取A組件傳入的數據顯示 {this.props.data}
# 8. 錯誤邊界

理解:

錯誤邊界(Error boundary):用來捕獲后代組件錯誤,渲染出備用頁面

特點:

只能捕獲后代組件生命周期產生的錯誤,不能捕獲自己組件產生的錯誤和其他組件在合成事件、定時器中產生的錯誤

使用方式:

getDerivedStateFromError配合componentDidCatch

// 生命周期函數,一旦后台組件報錯,就會觸發
static getDerivedStateFromError(error) {
    console.log(error);
    // 在render之前觸發
    // 返回新的state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // 統計頁面的錯誤。發送請求發送到后台去
    console.log(error, info);
}

9. 組件通信方式總結

組件間的關系:

  • 父子組件

  • 兄弟組件(非嵌套組件)

  • 祖孫組件(跨級組件)

幾種通信方式:

1.props:

(1).children props

(2).render props

2.消息訂閱-發布:

pubs-sub、event等等

3.集中式管理:

redux、dva等等

4.conText:

生產者-消費者模式

比較好的搭配方式:

父子組件:props

兄弟組件:消息訂閱-發布、集中式管理

祖孫組件(跨級組件):消息訂閱-發布、集中式管理、conText(開發用的少,封裝插件用的多)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM