組件通信
父組件與子組件通信
父組件將自己的狀態(tài)傳遞給子組件,子組件當(dāng)做屬性來接收,當(dāng)父組件更改自己狀態(tài)的時候,子組件接收到的屬性就會發(fā)生改變
父組件利用
ref
對子組件做標(biāo)記,通過調(diào)用子組件的方法以更改子組件的狀態(tài),也可以調(diào)用子組件的方法..
子組件與父組件通信
- 父組件將自己的某個方法傳遞給子組件,在方法里可以做任意操作籍救,比如可以更改狀態(tài)习绢,子組件通過
this.props
接收到父組件的方法后調(diào)用。
跨組件通信
在react沒有類似vue中的事件總線來解決這個問題蝙昙,我們只能借助它們共同的父級組件來實(shí)現(xiàn)闪萄,將非父子關(guān)系裝換成多維度的父子關(guān)系。react提供了context
api來實(shí)現(xiàn)跨組件通信, React 16.3之后的context
api較之前的好用奇颠。
實(shí)例败去,使用context
實(shí)現(xiàn)購物車中的加減功能
// counterContext.js
import React, { Component, createContext } from 'react'
?
const {
Provider,
Consumer: CountConsumer
} = createContext()
?
class CountProvider extends Component {
constructor () {
super()
this.state = {
count: 1
}
}
increaseCount = () => {
this.setState({
count: this.state.count + 1
})
}
decreaseCount = () => {
this.setState({
count: this.state.count - 1
})
}
render() {
return (
<Provider value={{
count: this.state.count,
increaseCount: this.increaseCount,
decreaseCount: this.decreaseCount
}}
>
{this.props.children}
</Provider>
)
}
}
?
export {
CountProvider,
CountConsumer
}
// 定義CountButton組件
const CountButton = (props) => {
return (
<CountConsumer>
// consumer的children必須是一個方法
{
({ increaseCount, decreaseCount }) => {
const { type } = props
const handleClick = type === 'increase' ? increaseCount : decreaseCount
const btnText = type === 'increase' ? '+' : '-'
return <button onClick={handleClick}>{btnText}</button>
}
}
</CountConsumer>
)
}
// 定義count組件,用于顯示數(shù)量
const Count = (prop) => {
return (
<CountConsumer>
{
({ count }) => {
return <span>{count}</span>
}
}
</CountConsumer>
)
}
// 組合
class App extends Component {
render () {
return (
<CountProvider>
<CountButton type='decrease' />
<Count />
<CountButton type='increase' />
</CountProvider>
)
}
}
復(fù)雜的非父子組件通信在react中很難處理烈拒,多組件間的數(shù)據(jù)共享也不好處理圆裕,在實(shí)際的工作中我們會使用flux、redux荆几、mobx來實(shí)現(xiàn)
HOC(高階組件)
Higher-Order Components就是一個函數(shù)吓妆,傳給它一個組件,它返回一個新的組件吨铸。
const NewComponent = higherOrderComponent(YourComponent)
比如行拢,我們想要我們的組件通過自動注入一個版權(quán)信息。
// withCopyright.js 定義一個高階組件
import React, { Component, Fragment } from 'react'
?
const withCopyright = (WrappedComponent) => {
return class NewComponent extends Component {
render() {
return (
<Fragment>
<WrappedComponent />
<div>©版權(quán)所有 千鋒教育 2019 </div>
</Fragment>
)
}
}
}
export default withCopyright
// 使用方式
import withCopyright from './withCopyright'
?
class App extends Component {
render () {
return (
<div>
<h1>Awesome React</h1>
<p>React.js是一個構(gòu)建用戶界面的庫</p>
</div>
)
}
}
const CopyrightApp = withCopyright(App)
這樣只要我們有需要用到版權(quán)信息的組件诞吱,都可以直接使用withCopyright這個高階組件包裹即可舟奠。
在這里要講解在CRA 中配置裝飾器模式的支持竭缝。
狀態(tài)管理
傳統(tǒng)MVC框架的缺陷
什么是MVC?
MVC
的全名是Model View Controller
沼瘫,是模型(model)-視圖(view)-控制器(controller)的縮寫抬纸,是一種軟件設(shè)計(jì)典范。
V
即View視圖是指用戶看到并與之交互的界面晕鹊。
M
即Model模型是管理數(shù)據(jù) 松却,很多業(yè)務(wù)邏輯都在模型中完成。在MVC的三個部件中溅话,模型擁有最多的處理任務(wù)晓锻。
C
即Controller控制器是指控制器接受用戶的輸入并調(diào)用模型和視圖去完成用戶的需求,控制器本身不輸出任何東西和做任何處理飞几。它只是接收請求并決定調(diào)用哪個模型構(gòu)件去處理請求砚哆,然后再確定用哪個視圖來顯示返回的數(shù)據(jù)。
MVC只是看起來很美
MVC框架的數(shù)據(jù)流很理想屑墨,請求先到Controller, 由Controller調(diào)用Model中的數(shù)據(jù)交給View進(jìn)行渲染躁锁,但是在實(shí)際的項(xiàng)目中,又是允許Model和View直接通信的卵史。然后就出現(xiàn)了這樣的結(jié)果:
Flux
在2013年战转,F(xiàn)acebook讓React
亮相的同時推出了Flux框架,React
的初衷實(shí)際上是用來替代jQuery
的以躯,Flux
實(shí)際上就可以用來替代Backbone.js
槐秧,Ember.js
等一系列MVC
架構(gòu)的前端JS框架。
其實(shí)Flux
在React
里的應(yīng)用就類似于Vue
中的Vuex
的作用忧设,但是在Vue
中刁标,Vue
是完整的mvvm
框架,而Vuex
只是一個全局的插件址晕。
React
只是一個MVC中的V(視圖層)膀懈,只管頁面中的渲染,一旦有數(shù)據(jù)管理的時候谨垃,React
本身的能力就不足以支撐復(fù)雜組件結(jié)構(gòu)的項(xiàng)目启搂,在傳統(tǒng)的MVC
中,就需要用到Model和Controller刘陶。Facebook對于當(dāng)時世面上的MVC框架并不滿意狐血,于是就有了Flux
, 但Flux
并不是一個MVC
框架,他是一種新的思想易核。
View: 視圖層
ActionCreator(動作創(chuàng)造者):視圖層發(fā)出的消息(比如mouseClick)
Dispatcher(派發(fā)器):用來接收Actions匈织、執(zhí)行回調(diào)函數(shù)
Store(數(shù)據(jù)層):用來存放應(yīng)用的狀態(tài),一旦發(fā)生變動,就提醒Views要更新頁面
Flux的流程:
組件獲取到store中保存的數(shù)據(jù)掛載在自己的狀態(tài)上
用戶產(chǎn)生了操作缀匕,調(diào)用actions的方法
actions接收到了用戶的操作纳决,進(jìn)行一系列的邏輯代碼、異步操作
然后actions會創(chuàng)建出對應(yīng)的action乡小,action帶有標(biāo)識性的屬性
actions調(diào)用dispatcher的dispatch方法將action傳遞給dispatcher
dispatcher接收到action并根據(jù)標(biāo)識信息判斷之后阔加,調(diào)用store的更改數(shù)據(jù)的方法
store的方法被調(diào)用后,更改狀態(tài)满钟,并觸發(fā)自己的某一個事件
store更改狀態(tài)后事件被觸發(fā)胜榔,該事件的處理程序會通知view去獲取最新的數(shù)據(jù)
Redux
React 只是 DOM 的一個抽象層,并不是 Web 應(yīng)用的完整解決方案湃番。有兩個方面夭织,它沒涉及。
代碼結(jié)構(gòu)
組件之間的通信
2013年 Facebook 提出了 Flux 架構(gòu)的思想吠撮,引發(fā)了很多的實(shí)現(xiàn)尊惰。2015年,Redux 出現(xiàn)泥兰,將 Flux 與函數(shù)式編程結(jié)合一起弄屡,很短時間內(nèi)就成為了最熱門的前端架構(gòu)。
如果你不知道是否需要 Redux鞋诗,那就是不需要它
只有遇到 React 實(shí)在解決不了的問題膀捷,你才需要 Redux
簡單說,如果你的UI層非常簡單削彬,沒有很多互動全庸,Redux 就是不必要的,用了反而增加復(fù)雜性吃警。
用戶的使用方式非常簡單
用戶之間沒有協(xié)作
不需要與服務(wù)器大量交互糕篇,也沒有使用 WebSocket
視圖層(View)只從單一來源獲取數(shù)據(jù)
需要使用Redux的項(xiàng)目:
用戶的使用方式復(fù)雜
不同身份的用戶有不同的使用方式(比如普通用戶和管理員)
多個用戶之間可以協(xié)作
與服務(wù)器大量交互啄育,或者使用了WebSocket
View要從多個來源獲取數(shù)據(jù)
從組件層面考慮酌心,什么樣子的需要Redux:
某個組件的狀態(tài),需要共享
某個狀態(tài)需要在任何地方都可以拿到
一個組件需要改變?nèi)譅顟B(tài)
一個組件需要改變另一個組件的狀態(tài)
Redux的設(shè)計(jì)思想:
Web 應(yīng)用是一個狀態(tài)機(jī)挑豌,視圖與狀態(tài)是一一對應(yīng)的安券。
所有的狀態(tài),保存在一個對象里面(唯一數(shù)據(jù)源)氓英。
注意:flux侯勉、redux都不是必須和react搭配使用的,因?yàn)閒lux和redux是完整的架構(gòu)铝阐,在學(xué)習(xí)react的時候址貌,只是將react的組件作為redux中的視圖層去使用了。
Redux的使用的三大原則:
Single Source of Truth(唯一的數(shù)據(jù)源)
State is read-only(狀態(tài)是只讀的)
Changes are made with pure function(數(shù)據(jù)的改變必須通過純函數(shù)完成)
自己實(shí)現(xiàn)Redux
這個部分,可以根據(jù)班級情況看是否講解练对。對于學(xué)生使用redux有很大的幫助遍蟋。不使用react,直接使用原生的html/js來寫一個簡易的的redux
基本的狀態(tài)管理及數(shù)據(jù)渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Redux principle 01</title>
</head>
<body>
<h1>redux principle</h1>
<div class="counter">
<span class="btn" onclick="dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span>
<span class="count" id="count"></span>
<span class="btn" id="add" onclick="dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span>
</div>
<script>
// 定義一個計(jì)數(shù)器的狀態(tài)
const countState = {
count: 10
}
?
// 定一個方法叫changeState螟凭,用于處理state的數(shù)據(jù)虚青,每次都返回一個新的狀態(tài)
const changeState = (action) => {
switch(action.type) {
// 處理減
case 'COUNT_DECREMENT':
countState.count -= action.number
break;
// 處理加
case 'COUNT_INCREMENT':
countState.count += action.number
break;
default:
break;
}
}
?
// 定義一個方法用于渲染計(jì)數(shù)器的dom
const renderCount = (state) => {
const countDom = document.querySelector('#count')
countDom.innerHTML = state.count
}
// 首次渲染數(shù)據(jù)
renderCount(countState)
?
// 定義一個dispatch的方法,接收到動作之后螺男,自動調(diào)用
const dispatch = (action) => {
changeState(action)
renderCount(countState)
}
?
</script>
</body>
</html>
創(chuàng)建createStore方法
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Redux principle 02</title>
</head>
<body>
<h1>redux principle</h1>
<div class="counter">
<span class="btn" onclick="store.dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span>
<span class="count" id="count"></span>
<span class="btn" id="add" onclick="store.dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span>
</div>
<script>
// 定義一個方法棒厘,用于集中管理state和dispatch
const createStore = (state, changeState) => {
// getState用于獲取狀態(tài)
const getState = () => state
// 定義一個監(jiān)聽器,用于管理一些方法
const listeners = []
const subscribe = (listener) => listeners.push(listener)
?
// 定義一個dispatch方法下隧,讓每次有action傳入的時候返回render執(zhí)行之后的結(jié)果
const dispatch = (action) => {
// 調(diào)用changeState來處理數(shù)據(jù)
changeState(state, action)
// 讓監(jiān)聽器里的所以方法運(yùn)行
listeners.forEach(listener => listener())
}
return {
getState,
dispatch,
subscribe
}
}
// 定義一個計(jì)數(shù)器的狀態(tài)
const countState = {
count: 10
}
// 定一個方法叫changeState奢人,用于處理state的數(shù)據(jù),每次都返回一個新的狀態(tài)
const changeState = (state, action) => {
switch(action.type) {
// 處理減
case 'COUNT_DECREMENT':
state.count -= action.number
break;
// 處理加
case 'COUNT_INCREMENT':
state.count += action.number
break;
default:
break;
}
}
?
// 創(chuàng)建一個store
const store = createStore(countState, changeState)
// 定義一個方法用于渲染計(jì)數(shù)器的dom
const renderCount = () => {
const countDom = document.querySelector('#count')
countDom.innerHTML = store.getState().count
}
// 初次渲染數(shù)據(jù)
renderCount()
// 監(jiān)聽汪拥,只要有dispatch达传,這個方法就會自動運(yùn)行
store.subscribe(renderCount)
</script>
</body>
</html>
讓changeState方法變?yōu)橐粋€純函數(shù)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Redux principle 03</title>
</head>
<body>
<h1>redux principle</h1>
<div class="counter">
<span class="btn" onclick="store.dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span>
<span class="count" id="count"></span>
<span class="btn" id="add" onclick="store.dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span>
</div>
<script>
// 定義一個方法,用于集中管理state和dispatch
const createStore = (state, changeState) => {
// getState用于獲取狀態(tài)
const getState = () => state
// 定義一個監(jiān)聽器迫筑,用于管理一些方法
const listeners = []
const subscribe = (listener) => listeners.push(listener)
?
// 定義一個dispatch方法宪赶,讓每次有action傳入的時候返回render執(zhí)行之后的結(jié)果
const dispatch = (action) => {
// 調(diào)用changeState來處理數(shù)據(jù)
state = changeState(state, action)
// 讓監(jiān)聽器里的所有方法運(yùn)行
listeners.forEach(listener => listener())
}
return {
getState,
dispatch,
subscribe
}
}
// 定義一個計(jì)數(shù)器的狀態(tài)
const countState = {
count: 10
}
// 定一個方法叫changeState,用于處理state的數(shù)據(jù)脯燃,每次都返回一個新的狀態(tài)
const changeState = (state, action) => {
switch(action.type) {
// 處理減
case 'COUNT_DECREMENT':
return {
...state,
count: state.count - action.number
}
// 處理加
case 'COUNT_INCREMENT':
return {
...state,
count: state.count + action.number
}
default:
return state
}
}
?
// 創(chuàng)建一個store
const store = createStore(countState, changeState)
// 定義一個方法用于渲染計(jì)數(shù)器的dom
const renderCount = () => {
const countDom = document.querySelector('#count')
countDom.innerHTML = store.getState().count
}
// 初次渲染數(shù)據(jù)
renderCount()
// 監(jiān)聽搂妻,只要有dispatch,這個方法就會自動運(yùn)行
store.subscribe(renderCount)
</script>
</body>
</html>
合并state和changeState(最終版)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Redux principle 04</title>
</head>
<body>
<h1>redux principle</h1>
<div class="counter">
<span class="btn" onclick="store.dispatch({type: 'COUNT_DECREMENT', number: 10})">-</span>
<span class="count" id="count"></span>
<span class="btn" id="add" onclick="store.dispatch({type: 'COUNT_INCREMENT', number: 10})">+</span>
</div>
<script>
// 定義一個方法辕棚,用于集中管理state和dispatch, changeState改名了欲主,專業(yè)的叫法是reducer
const createStore = (reducer) => {
// 定義一個初始的state
let state = null
// getState用于獲取狀態(tài)
const getState = () => state
// 定義一個監(jiān)聽器,用于管理一些方法
const listeners = []
const subscribe = (listener) => listeners.push(listener)
?
// 定義一個dispatch方法逝嚎,讓每次有action傳入的時候返回reducer執(zhí)行之后的結(jié)果
const dispatch = (action) => {
// 調(diào)用reducer來處理數(shù)據(jù)
state = reducer(state, action)
// 讓監(jiān)聽器里的所有方法運(yùn)行
listeners.forEach(listener => listener())
}
// 初始化state
dispatch({})
return {
getState,
dispatch,
subscribe
}
}
// 定義一個計(jì)數(shù)器的狀態(tài)
const countState = {
count: 10
}
// 定一個方法叫changeState扁瓢,用于處理state的數(shù)據(jù),每次都返回一個新的狀態(tài)
const changeState = (state, action) => {
// 如果state是null, 就返回countState
if (!state) return countState
switch(action.type) {
// 處理減
case 'COUNT_DECREMENT':
return {
...state,
count: state.count - action.number
}
// 處理加
case 'COUNT_INCREMENT':
return {
...state,
count: state.count + action.number
}
default:
return state
}
}
?
// 創(chuàng)建一個store
const store = createStore(changeState)
// 定義一個方法用于渲染計(jì)數(shù)器的dom
const renderCount = () => {
const countDom = document.querySelector('#count')
countDom.innerHTML = store.getState().count
}
// 初次渲染數(shù)據(jù)
renderCount()
// 監(jiān)聽补君,只要有dispatch引几,renderCount就會自動運(yùn)行
store.subscribe(renderCount)
</script>
</body>
</html>
使用Redux框架
Redux的流程:
1.store通過reducer創(chuàng)建了初始狀態(tài)
2.view通過store.getState()獲取到了store中保存的state掛載在了自己的狀態(tài)上
3.用戶產(chǎn)生了操作,調(diào)用了actions 的方法
4.actions的方法被調(diào)用挽铁,創(chuàng)建了帶有標(biāo)示性信息的action
5.actions將action通過調(diào)用store.dispatch方法發(fā)送到了reducer中
6.reducer接收到action并根據(jù)標(biāo)識信息判斷之后返回了新的state
7.store的state被reducer更改為新state的時候伟桅,store.subscribe方法里的回調(diào)函數(shù)會執(zhí)行,此時就可以通知view去重新獲取state
Reducer必須是一個純函數(shù):
Reducer 函數(shù)最重要的特征是叽掘,它是一個純函數(shù)楣铁。也就是說,只要是同樣的輸入更扁,必定得到同樣的輸出盖腕。Reducer不是只有Redux里才有赫冬,之前學(xué)的數(shù)組方法reduce
, 它的第一個參數(shù)就是一個reducer
純函數(shù)是函數(shù)式編程的概念,必須遵守以下一些約束溃列。
不得改寫參數(shù)
不能調(diào)用系統(tǒng) I/O 的API
不能調(diào)用Date.now()或者M(jìn)ath.random()等不純的方法面殖,因?yàn)槊看螘玫讲灰粯拥慕Y(jié)果
由于 Reducer 是純函數(shù),就可以保證同樣的State哭廉,必定得到同樣的 View脊僚。但也正因?yàn)檫@一點(diǎn),Reducer 函數(shù)里面不能改變 State遵绰,必須返回一個全新的對象辽幌,請參考下面的寫法。
// State 是一個對象
function reducer(state = defaultState, action) {
return Object.assign({}, state, { thingToChange });
// 或者
return { ...state, ...newState };
}
?
// State 是一個數(shù)組
function reducer(state = defaultState, action) {
return [...state, newItem];
}
最好把 State 對象設(shè)成只讀椿访。要得到新的 State乌企,唯一辦法就是生成一個新對象。這樣的好處是成玫,任何時候加酵,與某個 View 對應(yīng)的 State 總是一個不變(immutable)的對象。
我們可以通過在createStore中傳入第二個參數(shù)來設(shè)置默認(rèn)的state哭当,但是這種形式只適合于只有一個reducer的時候猪腕。
劃分reducer:
因?yàn)橐粋€應(yīng)用中只能有一個大的state,這樣的話reducer中的代碼將會特別特別的多钦勘,那么就可以使用combineReducers方法將已經(jīng)分開的reducer合并到一起
注意: 1陋葡、分離reducer的時候,每一個reducer維護(hù)的狀態(tài)都應(yīng)該不同 2彻采、通過store.getState獲取到的數(shù)據(jù)也是會按照reducers去劃分的 3腐缤、劃分多個reducer的時候,默認(rèn)狀態(tài)只能創(chuàng)建在reducer中肛响,因?yàn)閯澐謗educer的目的岭粤,4、就是為了讓每一個reducer都去獨(dú)立管理一部分狀態(tài)
最開始一般基于計(jì)數(shù)器的例子講解redux的基本使用即可特笋。
關(guān)于action/reducer/store的更多概念剃浇,請查看官網(wǎng)
Redux異步
通常情況下,action只是一個對象雹有,不能包含異步操作偿渡,這導(dǎo)致了很多創(chuàng)建action的邏輯只能寫在組件中臼寄,代碼量較多也不便于復(fù)用霸奕,同時對該部分代碼測試的時候也比較困難,組件的業(yè)務(wù)邏輯也不清晰吉拳,使用中間件了之后质帅,可以通過actionCreator異步編寫action,這樣代碼就會拆分到actionCreator中,可維護(hù)性大大提高煤惩,可以方便于測試嫉嘀、復(fù)用,同時actionCreator還集成了異步操作中不同的action派發(fā)機(jī)制魄揉,減少編碼過程中的代碼量
常見的異步庫:
Redux-thunk(就講這個)
Redux-saga
Redux-effects
Redux-side-effects
Redux-loop
Redux-observable
…
基于Promise的異步庫:
Redux-promise
Redux-promises
Redux-simple-promise
Redux-promise-middleware
…
容器組件(Smart/Container Components)和展示組件(Dumb/Presentational Components)
使用react-redux
可以先結(jié)合context
來手動連接react和redux剪侮。
react-redux提供兩個核心的api:
Provider: 提供store
connect: 用于連接容器組件和展示組件
Provider 根據(jù)單一store原則 ,一般只會出現(xiàn)在整個應(yīng)用程序的最頂層洛退。
connect 語法格式為
connect(mapStateToProps?, mapDispatchToProps?, mergeProps?, options?)(component)
一般來說只會用到前面兩個瓣俯,它的作用是:
把
store.getState()
的狀態(tài)轉(zhuǎn)化為展示組件的props
把
actionCreators
轉(zhuǎn)化為展示組件props
上的方法
特別強(qiáng)調(diào): 官網(wǎng)上的第二個參數(shù)為mapDispatchToProps, 實(shí)際上就是actionCreators
只要上層中有Provider
組件并且提供了store
, 那么,子孫級別的任何組件兵怯,要想使用store
里的狀態(tài)彩匕,都可以通過connect
方法進(jìn)行連接。如果只是想連接actionCreators
媒区,可以第一個參數(shù)傳遞為null
React Router
React Router現(xiàn)在的版本是5, 于2019年3月21日搞笑的發(fā)布驼仪,搞笑的官網(wǎng)鏈接熟妓, 本來是要發(fā)布4.4的版本的赞赖,結(jié)果成了5。從4開始厕宗,使用方式相對于之前版本的思想有所不同宙攻。之前版本的思想是傳統(tǒng)的思想:路由應(yīng)該統(tǒng)一在一處渲染毡泻, Router 4之后是這樣的思想:一切皆組件
React Router包含了四個包:
主要使用react-router-dom
使用方式
正常情況下,直接按照官網(wǎng)的demo就理解 路由的使用方式粘优,有幾個點(diǎn)需要特別的強(qiáng)調(diào):
- Route組件的exact屬性
exact
屬性標(biāo)識是否為嚴(yán)格匹配仇味, 為true
是表示嚴(yán)格匹配,為false
時為正常匹配雹顺。
- Route組件的render屬性而不是component屬性
怎么在渲染組件的時候丹墨,對組件傳遞屬性呢?使用component
的方式是不能直接在組件上添加屬性的嬉愧。所以贩挣,React Router的Route
組件提供了另一種渲染組件的方式render
, 這個常用于頁面組件級別的權(quán)限管理。
路由的參數(shù)傳遞與獲取
Switch組件
總是渲染第一個匹配到的組件
處理404與默認(rèn)頁
withRoute高階組件的使用
管理一個項(xiàng)目路由的方法
HashRouter和BrowserRouter的區(qū)別没酣,前端路由和后端路由的區(qū)別王财。這個在Vue里應(yīng)該有講過了。
React Router基本原理
React Router甚至大部分的前端路由都是依賴于history.js的裕便,它是一個獨(dú)立的第三方j(luò)s庫绒净。可以用來兼容在不同瀏覽器偿衰、不同環(huán)境下對歷史記錄的管理挂疆,擁有統(tǒng)一的API改览。
老瀏覽器的history: 通過
hash
來存儲在不同狀態(tài)下的history信息,對應(yīng)createHashHistory
缤言,通過檢測location.hash
的值的變化宝当,使用location.replace
方法來實(shí)現(xiàn)url跳轉(zhuǎn)。通過注冊監(jiān)聽window
對象上的hashChange
事件來監(jiān)聽路由的變化胆萧,實(shí)現(xiàn)歷史記錄的回退庆揩。高版本瀏覽器: 利用HTML5里面的
history
,對應(yīng)createBrowserHistory
, 使用包括pushState
跌穗,replaceState
方法來進(jìn)行跳轉(zhuǎn)盾鳞。通過注冊監(jiān)聽window
對象上的popstate
事件來監(jiān)聽路由的變化,實(shí)現(xiàn)歷史記錄的回退瞻离。node環(huán)境下: 在內(nèi)存中進(jìn)行歷史記錄的存儲腾仅,對應(yīng)
createMemoryHistory
。直接在內(nèi)存里push
和pop
狀態(tài)套利。