React學(xué)習(xí)筆記(四)

組件通信

父組件與子組件通信

  • 父組件將自己的狀態(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之后的contextapi較之前的好用奇颠。

實(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>&copy;版權(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í)FluxReact里的應(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的流程:

  1. 組件獲取到store中保存的數(shù)據(jù)掛載在自己的狀態(tài)上

  2. 用戶產(chǎn)生了操作缀匕,調(diào)用actions的方法

  3. actions接收到了用戶的操作纳决,進(jìn)行一系列的邏輯代碼、異步操作

  4. 然后actions會創(chuàng)建出對應(yīng)的action乡小,action帶有標(biāo)識性的屬性

  5. actions調(diào)用dispatcher的dispatch方法將action傳遞給dispatcher

  6. dispatcher接收到action并根據(jù)標(biāo)識信息判斷之后阔加,調(diào)用store的更改數(shù)據(jù)的方法

  7. store的方法被調(diào)用后,更改狀態(tài)满钟,并觸發(fā)自己的某一個事件

  8. 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ì)思想:

  1. Web 應(yīng)用是一個狀態(tài)機(jī)挑豌,視圖與狀態(tài)是一一對應(yīng)的安券。

  2. 所有的狀態(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: 用于連接容器組件和展示組件

  1. Provider 根據(jù)單一store原則 ,一般只會出現(xiàn)在整個應(yīng)用程序的最頂層洛退。

  2. 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)目路由的方法

  • code spliting

  • 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)存里pushpop狀態(tài)套利。


?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末推励,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子肉迫,更是在濱河造成了極大的恐慌验辞,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,539評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件喊衫,死亡現(xiàn)場離奇詭異跌造,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)族购,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,594評論 3 396
  • 文/潘曉璐 我一進(jìn)店門壳贪,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人寝杖,你說我怎么就攤上這事违施。” “怎么了瑟幕?”我有些...
    開封第一講書人閱讀 165,871評論 0 356
  • 文/不壞的土叔 我叫張陵磕蒲,是天一觀的道長。 經(jīng)常有香客問我只盹,道長辣往,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,963評論 1 295
  • 正文 為了忘掉前任殖卑,我火速辦了婚禮站削,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘懦鼠。我一直安慰自己钻哩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,984評論 6 393
  • 文/花漫 我一把揭開白布肛冶。 她就那樣靜靜地躺著街氢,像睡著了一般。 火紅的嫁衣襯著肌膚如雪睦袖。 梳的紋絲不亂的頭發(fā)上珊肃,一...
    開封第一講書人閱讀 51,763評論 1 307
  • 那天,我揣著相機(jī)與錄音馅笙,去河邊找鬼伦乔。 笑死,一個胖子當(dāng)著我的面吹牛董习,可吹牛的內(nèi)容都是我干的烈和。 我是一名探鬼主播,決...
    沈念sama閱讀 40,468評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼皿淋,長吁一口氣:“原來是場噩夢啊……” “哼招刹!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起窝趣,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤疯暑,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后哑舒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體妇拯,經(jīng)...
    沈念sama閱讀 45,850評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,002評論 3 338
  • 正文 我和宋清朗相戀三年洗鸵,在試婚紗的時候發(fā)現(xiàn)自己被綠了越锈。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,144評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡膘滨,死狀恐怖瞪浸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情吏祸,我是刑警寧澤对蒲,帶...
    沈念sama閱讀 35,823評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站贡翘,受9級特大地震影響蹈矮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜鸣驱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,483評論 3 331
  • 文/蒙蒙 一泛鸟、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧踊东,春花似錦北滥、人聲如沸刚操。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,026評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽菊霜。三九已至,卻和暖如春济赎,著一層夾襖步出監(jiān)牢的瞬間鉴逞,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,150評論 1 272
  • 我被黑心中介騙來泰國打工司训, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留构捡,地道東北人。 一個月前我還...
    沈念sama閱讀 48,415評論 3 373
  • 正文 我出身青樓壳猜,卻偏偏與公主長得像勾徽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子统扳,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,092評論 2 355