React總結

一. react-router-dom

簡介: React Router是一個基於 React 之上的強大路由庫,它可讓你嚮應用中快速地添加視圖和數據流,同時保持頁面與URL間的同步。html

router共包含如下幾種:
react-router: React Router 核心
react-router-dom: 用於 DOM 綁定的 React Router
react-router-native: 用於React Native 的 React Router
react-router-redux: React Router 和 Redux的集成
react-router-config: 靜態路由配置的小助手

說明:
今天咱們主要說的是 react-router-dom
react-router-dom包含 HisitoryRouter BrowserRouter等
注意:使用react-router-dom時,只須要引入react-router-dom就能夠了,不須要引入react-router


<BrowserRouter>

使用

import { BrowserRouter, NavLink, Switch, Redirect} from 'react-router-dom'

<BrowserRouter basename={`${path}`}>
  <ul id="menu">
     <NavLink activeClassName={styles.active} exact to={`/`} />
     <NavLink activeClassName={styles.active} to={`/user`} />
  </ul>
  <div id='page-container' className={styles.container}>
   <Switch>
      <Route path={`/`} exact component={main} />
      <Route path={`/user`} render={(props) => <User pageId="user" />} />
      <Redirect to="/" />
    </Switch>
   </div>
</BrowserRouter>

// NavLink添加activeClassName屬性以後可讓首頁tab默認選中
複製代碼
<Switch>
    <Route exact path="/app/" render={() => 
    <Redirect to='/app/error'></Redirect>}></Route>
    <Route path="/app/users" component={Users}></Route>
    <Route path="/app/report" component={Report}></Route> 
    <Route path="/app/error" component={ErrorPage}></Route>
    <Redirect to="/app/" />
</Switch>

說明:
一、地址欄輸入 /app/user ,跳轉到指定的Users組件
二、exact指定輸入 /app/重定向redirect to /app/error,重定向到ErrorPage組件中
3. 若是輸入錯誤的地址,重定向到/app/路由,跳轉到ErrorPage組件中
注意:重定向分兩種 1.指定重定向,2.模糊重定向



複製代碼

<Switch> 只渲染出第一個與當前地址匹配的<Route><Redirect>node

Switch解決的問題:若是你訪問/about,那麼與/about相關的路徑都將被渲染出來,如/about/user,由於他們對應的路由與訪問的地址/about匹配。這顯然不是咱們想要的,咱們只想渲染出第一個匹配的路由就能夠了,因而<Switch>應用而生!react

Historyredux

pushState()瀏覽器

popstate性能優化

路由實現 - history

<header>
  <a onclick="changeRoute(this)" data-path="home">首頁</a>
  <a onclick="changeRoute(this)" data-path="center">我的中心</a>
  <a onclick="changeRoute(this)" data-path="help">幫助</a>
</header>
<section id="content"></section>
<script>
/**
Hisotory.pushState(state, title, url) 按指定的名稱和URL(若是提供該參數)將數據push進回話歷史棧。

state: 一個與添加的記錄相關聯的狀態對象,主要用於popstate事件,該事件觸發時,該對象會傳入回調函數。也就是說,瀏覽器會將這個對象序列化之後保留在本地,從新載入這個頁面的時候,能夠拿到這個對象。若是不須要這個對象,此處能夠填爲null

title: 新頁面的標題。可是,如今全部瀏覽器都忽視這個參數,因此這裏能夠填空字符串。

url: 新的網址,必須與當前頁面處在同一個域。瀏覽器的地址欄將顯示這個地址。

*/
  function changeRoute (route) {
      let path = route.dataset.path
      
      changePage(path)
      history.pushState({content: path}, null, path)
  }
  /**

  當活動歷史記錄條目更改時,將觸發popstate事件。history.pushState()的調用建立的,或者受到對 history.replaceState()的調用的影響,popstate事件的state屬性包含歷史條目的狀態對象的副本。
  
  history.pushState() 或者 history.replaceState()不會觸發popstate事件。只有在作出瀏覽器動做時,纔會觸發該事件,如用戶點擊瀏覽器的回退按鈕 或者在js代碼中調用history.back()
  
  */
  window.addEventListener('popstate', (e) => {
      let content = e.state && e.state.content
      changePage(content)
  })
  
  function changePage (pageContent) {
      let content = document.getElementById('content')
      content.innerText = pageContent
  }
</script>
複製代碼
  • BrowerRouterbash

    <BrowerRouter>使用HTML5的history API (pushStatereplacestate popstate事件)來同步URL和UI服務器

<BrowerRouter basename={optionalString} forceRefresh={optionlBool} getUserConfirmation={optionlFunc} keyLength={optionlNumber}>
<App/>
</BrowerRouter>
複製代碼

屬性介紹babel

basename: string:基準URL.適用於當應用置於服務器上子目錄的狀況下。數據結構

forceRefresh: bool: 當設爲true時,每次跳轉都會刷新頁面。通常只在瀏覽器不支持HTML history API的狀況下使用。

getUserConfirmation: func: 能夠傳入一個函數,用來肯定導航前的用戶確認行爲,默認使用window.confirm,以下:

keyLength: number: 設置location.key的長度,默認爲6位

children: node:子元素裏只能渲染單一的元素

  • HashRouter

    使用URL中的hash部分(即window.location.hash)來保持UI和URL同步

    注意:HashHistory不支持location.keylocation.state,因此任何須要這兩個屬性的代碼或者插件將不能起做用。因爲HashHisitory這種技術的主要目的是支持老式瀏覽器,因此官方更推薦的作法是對服務器進行配置,而後採用<BrowerRouter>代替。

  • MemoryRouter

    在內存中記錄history的路由組件(這種路由不會讀取或者寫入地址欄),適合用於測試或者非瀏覽器環境(如ReactNative

導航跳轉

  1. Link

爲應用提供聲明式、可訪問的導航的一個組件:

import { Link } from 'react-router-dom'
<Link to="/about">About</Link>
複製代碼

參數: to: string 要跳轉到的 pathname 或者 location

to: object

用法:

<Link to={{
      pathname: '/course', 
      search: '?sort=name',
      hash: '#the-hash',
      state: { fromDashboard: true }
}} />
複製代碼

replace: bool 當這個值爲 true 時,會替換掉history棧裏當前的history,而不是在棧裏新增一條history,如:

<Link to="/courses" replace>
複製代碼
  1. NavLink

<Link>組件的特殊版本,當前URL匹配時,會在元素上增長樣式相關的屬性activeClassName,從而達到高亮標記的效果。

import { NavLink } from 'react-router-dom'
<NavLink to="/about">About</NavLink>
複製代碼

參數:

activeClassName: string 規定處於激活狀態時的類名,默認值是active,會自動和className屬性合併:

<NavLink to="/faq" activeClassName="selected">FAQs</NavLink>
複製代碼

activeStyle: object 規定激活狀態下應用到元素上的樣式:

<NavLink to="/faq" activeStyle={{
    fontWeight: 'bold',
    color: 'red'
}}>FAQs</NavLink>
複製代碼

exact: bool設爲true時,只有當location徹底匹配的時候纔會添加類名或者樣式: 與Switch的區別

<NavLink exact to="/profile">Profile</NavLink>
複製代碼

strict: bool:當設爲 true時,location中pathname末尾的/就會在匹配URL的時候被考慮: 就是說有/和沒有/的結果徹底不一樣

<NavLink strict to="/events/">Events</NavLink>
複製代碼

isActive: func:用來爲link添加判斷激活狀態額外邏輯的函數,如:

isActive能夠經過邏輯來控制

// 只有當事件ID爲奇數時纔可能爲激活狀態
const oddEvent = (match, location) => {
    if (!match) {
        return false
    }
    const eventID = parseInt(match.params.eventID)
    return !isNaN(eventID) && eventID % 2 === 1
}

<NavLink to="/events/263" isActive={oddEvent}>Event 263</NavLink>
複製代碼

location: object

isActive函數裏用來比較用的值(即傳入的第二個參數),一般狀況下取值爲當前瀏覽器的URL.若是要和不一樣的location比較,就能夠用這個屬性來傳值。

<NavLink activeClassName={styles.active} exact to={`/`} />
複製代碼

二. Router、Route與Switch 一、Router 通用的基礎路由組件。一般在應用裏會採用派生的路由代替,有:

<BrowserRouter> <HashRouter> <MemoryRouter> <NativeRouter> <StaticRouter>

最經常使用的直接採用<Router>的場景是用狀態管理庫(Redux、Mobx)來同步一個自定義的history。不過應當注意的是:這不是說必須結合狀態管理庫使用ReactRouter,只是在深度集成的時候須要用到:

import { Router } from 'react-router'
import createBrowserHistory from 'history/createBrowserHistory'

const history = createBrowserHistory()
<Router history={history}>
    <App />
</Router>
複製代碼

參數:

history: object 用來導航用的history對象

二、Route

組件也許是ReactRouter裏最須要好好理解和使用的最重要的一個組件。它的基本職責是在location匹配路由的path參數值時渲染特定的UI:

import { BrowserRouter as Router, Route } from 'react-router-dom'
<Router>
    <div>
        <Route exact path="/" component={Home} />
        <Route path="/news" component={NewsFeed} />
    </div>
</Router>
複製代碼

當location是/時,UI將會渲染爲:

<div>
    <Home />
    <!-- react-empty: 2 -->
</div>
複製代碼

而若是當UI是/news時,UI將會渲染爲:

<div>
    <!-- react-empty: 1 -->
    <NewsFeed />
</div>
複製代碼

react-empty註釋,只是React的null渲染的實現。可是這種作法是有益的,從技術上而言一個Route應該老是被渲染出來即便結果是渲染null,而只要應用的location和Route的path匹配,那麼對應的組件就會獲得渲染。

2-一、路由渲染方法

渲染一個路由有三種方式:

<Route component> <Route render> <Route children>

每一種方式在不一樣的情景下都是有用的,可是在<Route>裏只能同時用一個屬性,不過大部分狀況下用的是component

注意: 因爲優先級上:component > render > children,因此在<Route>裏最多隻能選用一種。

首先須要知道的是,這三種方式都會獲得match、location、history這三個路由屬性。

說明:

component方式,代表location匹配時要渲染的React組件,組件可使用路由屬性來進行渲染:

<Route path="/user/:username" component={User} />

const User = ({ match }) => {
    return <h1>Hello, {match.params.username}!</h1>
}
複製代碼

當使用這種方式時,路由系統會使用React.createElement來從給定的組件裏建立一個新的React元素。這意味着若是傳給component屬性的是一個內聯的函數,那麼每次渲染時就都會 建立一個新的組件。這就會致使現有的組件卸載,而後掛載新的組件。而非更新已有的組件。因此要使用內聯函數來進行內聯渲染時,可使用render方式或者children方式

render: func方式,這種方式將方便於內聯渲染,而且不會有上述的從新掛載問題。咱們能夠傳入一個函數,那麼當location匹配的時候這個函數就會被調用,從而不會進行新的React元素建立過程。render屬性接收和component屬性一致的路由屬性:

<Route path="/home" render={() => <div>Home</div>} />

const FadingRoute = ({ component: Component, ...rest }) => (
    <Route {...rest} render={props => (
        <FadeIn>
            <Component {...props} />
        </FadeIn>
    )} />
)

<FadingRoute path="/cool" component={Something} />
複製代碼

children: func方式,有時候,不管path是否成功匹配都須要進行渲染。那麼這種狀況下,可使用children屬性方式,這種方式不管匹配是否成功都會調用對應的函數。 而children渲染屬性接收和component、render方式同樣的屬性,不過當路由不匹配的時候,match的值是null。因此採用這種方式的好處是,咱們能夠靈活地動態調整UI,不管路由是否匹配。舉例如:

路由匹配時添加激活狀態的類名:

<ul>
    <ListItemLink to="/somewhere" />
    <ListItemLink to="/somewhere-else" />
</ul>

const ListItemLink = ({to, ...rest}) => (
    <Route path={to} children={({ match }) => (
        <li className={match ? 'active' : ''}>
            <Link to={to} {...rest} />
        </li>
    )}/>
)
複製代碼

對於動畫而言,這種方式也是有用的:

<Route children={({ match, ...rest }) => (
    // 由於動畫會一直渲染,因此可使用生命週期來讓子元素動畫進出
    <Animate>
        {match && <Something {...rest}/>}
    </Animate>
)}
複製代碼

三、Switch

渲染子元素裏第一個匹配的<Route>或者<Redirect>,那麼,和只使用一堆<Route>不一樣的是什麼? <Switch>獨一無二的是它只渲染一個路由。而反過來,每一個匹配location的<Route>都會被獲得渲染,參考以下代碼:

<Route path="/about" component={About} />
<Route path="/:user" component={User} />
<Route component={NoMatch} />
複製代碼

若是URL是/about,那麼<About><User><NoMatch>都會渲染,由於它們的path都獲得了匹配。而這種設計是有意的,由於這使得咱們能夠用多種方式來用<Route>組成咱們的應用,如側邊欄、麪包屑、引導Tab等。

不過有時候,咱們只想要拾取一個<Route>來渲染,就好比URL處於/about時就不但願它匹配/:user(或者展現404頁面),如:

import { Switch, Route } from 'react-router'
<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/about" component={About} />
    <Route path="/:user" component={User} />
    <Route component={NoMatch} />
</Switch>
複製代碼

如今,若是URL是/about,那麼<Switch>就會開始尋找匹配的<Route><Route path="/about"/>將會匹配,從而<Switch>就會中止匹配而後渲染出<About>組件。類似地,若是URL處於/michael,那麼<User>組件就會渲染。

對於動畫過渡而言,這也是一種有用的方式,由於匹配的<Route>須要渲染在先前相同的位置:

<Fade>
    <Switch>
        {/* 這裏只會有一個子節點 */}
        <Route/>
        <Route/>
    </Switch>
</Fade>

<Fade>
    <Route/>
    <Route/>
    {/* 
        這裏一直都會有兩個子節點,儘管其中一個可能爲null,
        這會使得過渡效果起效果有點難處理
    */}
</Fade>
複製代碼

參數說明:

location: object 和以前其餘地方里含義一致 children: node <Switch>組件的子元素都應該是<Router>或者<Redirect>,而且只有匹配當前URL的第一個子元素會被渲染。其中,<Route>元素使用path屬性來進行匹配,而<Redirect>使用from屬性進行匹配。而不帶path屬性的<Route>元素或者不帶from屬性的<Redirect>元素會老是匹配當前location 因此當在<Switch>裏使用<Redirect>組件時,它可使用和<Route>同樣的匹配屬性:path、exact、strict,而from只是path屬性的別名。

當給<Switch>傳入location屬性時,會覆蓋當前匹配的子元素中的location

<Switch>
    <Route exact path="/" component={Home} />
    <Route path="/users" component={Users} />
    <Redirect from="/accounts" to="/users" />
    <Route component={NoMatch} />
</Switch>
複製代碼
  1. redux
異步獲取數據
複製代碼
  1. 高階組件
複製代碼
  1. 程序設計
在接口的設計上應體現出數據與業務的相分離。下降耦合性。在代碼的設計上也要儘可能下降重複性代碼。在寫代碼以前要清楚接口的數據結構,設計好代碼結構,儘可能減小在寫代碼時候頻繁修改代碼。
複製代碼
  1. dangerouslySetInnerHTML

7.API

react中最重要的三個API: createElement 、render、 component

component(react中一切皆組件)中包含setState

virtual Dom

jsx表面看是HTML標籤,其實是下面這套內容

React.createElement(
"div",
null,
"hello ",
this.props.name,
" ,I am",
{2 + 2},
"years old"
)
複製代碼

是jsx的babel作的編譯,jsx表面是html,其實是js

React.createElement返回的數據

JSX本質上就是轉換爲React.createElement在react內部構建虛擬dom,最終渲染出頁面

React.createElement是用來建立虛擬DOM的

React.createElement是一個遞歸調用的過程,也就是說dom中嵌套dom,會嵌套相應個數的React.createElement

學習一個庫的最好方法,先開發一個小應用,而後嘗試理解源碼。

參考連接:ReactRouter4學習筆記

2、分析執行流程

<div>
  <A />
  <B>
    <C />
    <D />
  </B>
</div>
複製代碼

請說出componentWillUpdatecomponentDidUpdateA B C D四個組件的執行順序。

  1. componentWillMount
A B C D
複製代碼
  1. componentDidMount
A C D B
複製代碼

3、PureComponent

原理:當組件更新時,若是組件的props和state都沒發生改變,render方法都不會觸發,省去Virtual DOM的生成和對比過程,達到提高性能的目的。React自動幫咱們作了一層淺比較。 PureComponent真正起做用的,只是在一些純展現組件上,複雜組件使用的話shallowEqual那一關基本就過不了。

shouldComponentUpdate

React性能優化

不可變數據的力量,返回新對象,而不是修改老對象。

大部分狀況下,可使用 React.PureComponent 來代替手寫 shouldComponentUpdate。

4、setState

  1. setState只在合成事件和鉤子函數中是"異步"的,在原生事件和setTimeout中都是同步的。
  2. setState的"異步"並非說內部由異步代碼實現,其實自己執行的過程和代碼都是同步的,只是合成事件和鉤子函數的調用順序在更新以前,致使在合成事件和鉤子函數中無法立馬拿到更新後的值,造成了所謂的「異步」,也能夠經過第二個參數 setState(partialState, callback) 中的callback拿到更新後的結果。
  3. setState的批量更新優化也是創建在「異步」(合成事件、鉤子函數)之上的,在原生事件和setTimeout中不會批量更新,在「異步」中若是對一個值進行屢次setState,setState的批量更新策略會對其進行覆蓋,取最後一次的執行,若是是同時setState多個不一樣的值,在更新時會對其進行合併批量更新。

5、readux-thunk中間件原理

redux-thunk爲何能讓action發送函數 redux-thunk是對dispatch方法作一個升級,以前這個dispatch方法只能接收一個對象,升級以後,就能夠接收函數了。根據參數的不一樣執行不一樣的事情,若是是對象就直接傳遞給store,若是是函數就先執行函數,在調用dispatch。原理就是對store的dispatch方法作了一個升級。

4、Props.childern

相關文章
相關標籤/搜索