React爬坑之路二:Router+Redux

上一篇寫了Antd和Axios的基本操作
之前大標題到五了那么這篇從六開始
ST也是初學小白可能講的完全不對
大家當做小說隨便讀讀消遣一下就好

React官網(wǎng):https://reactjs.org/
菜鳥教程:http://www.runoob.com/react/react-tutorial.html
ES6入門: http://es6.ruanyifeng.com/
Ant Design:https://ant.design/index-cn
Redux: https://www.redux.org.cn/
Dva:https://github.com/dvajs/dva

先附上上一篇的鏈接。React爬坑之路一:React+Antd+Axios
在真正研究Dva前回梧,我們除了先了解一些ES6葫辐,React,Antd蕉朵,Axios的基本知識万牺,還需要知道Router和Redux的工作原理枫弟。

六.React-Router配置路由

在實際應用中彩匕,我們不可能只有一頁頁面,切換頁面需要通過Router配置媒区,這樣輸入不同的url就能看到不同的頁驼仪,或者點擊不同的按鈕可以在下方加載不同的組件。
這里補充一下組件的概念袜漩,其實其本質(zhì)就是一個類绪爸。在頁面中我們可以把頁面分為導航區(qū),側(cè)邊欄宙攻,工作區(qū)等不同區(qū)域奠货,每個區(qū)域都是一個組件,組件中還可以繼續(xù)細分為其他組件座掘。想象在創(chuàng)建頁面的時候把不同的組件拿來組合在一起递惋,頁頭頁尾這種公用組件可以始終保持不動,只切換我們想切換的區(qū)域溢陪。)
一般來講萍虽,我們用React-router-dom來實現(xiàn),它提供了BrowserRouter, Route, Link等api形真,讓我們可以通過dom事件控制路由杉编。
第一步還是安裝。

npm install react-router-dom --save

這時我們新建兩個組件aaa.js和bbb.js。

import React, { Component } from 'react';

class AAA extends Component {
    render() {
        return (
            <div>
                <h1>AAA</h1>
            </div>
        )
    }
}
export default AAA;
import React, { Component } from 'react';

class BBB extends Component {
    render() {
        return (
            <div>
                <h1>BBB</h1>
            </div>
        )
    }
}
export default BBB;

并且在首頁上搞兩個按鈕邓馒。(不會搞的請去看上一篇)

假裝是導航.png

然后嘶朱,將剛剛的兩個組件,和React-router-dom中的一些api導入首頁app.js光酣。這里我們用了BrowserRouter疏遏,當然也可以用HashRouter,差別就是地址欄有沒有#救军。嗯比如用HashRouter地址欄就是http://localhost:3000/#/财异。(好像還有別的差別但是我不知道Σ(⊙▽⊙"))

import { BrowserRouter, Route, Link, Switch } from 'react-router-dom';  
import AAA from './aaa';
import BBB from './bbb';

然后在Dom里用Link來改變地址欄的url,注意Link缤言,Route這些api都需要寫在<BrowserRouter>

    <BrowserRouter>  
      <div className="App">
        <Button type="primary"><Link to='/aaa'>假裝自己是個導航</Link></Button>
        <Button><Link to='/bbb'>假裝自己是另一個</Link></Button>
      </div>
    </BrowserRouter>  

此時點擊按鈕可以看到地址欄是改變的宝当,會變成http://localhost:3000/aaahttp://localhost:3000/bbb视事。
然后胆萧,在下方加上要通過路由切換的組件,當path為aaa或者bbb的時候分別加載AAA和BBB俐东。

    <BrowserRouter>  
      <div className="App">
        <Button type="primary"><Link to='/aaa'>假裝自己是個導航</Link></Button>
        <Button><Link to='/bbb'>假裝自己是另一個</Link></Button>
        <Switch>
            <Route path="/aaa" exact component={AAA} />
            <Route path="/bbb" exact component={BBB} />
        </Switch>
      </div>
    </BrowserRouter>  

此時跌穗,在瀏覽器中點擊兩個按鈕,應該能看到下方可以切換兩種組件啦虏辫。

AAA.png
BBB.png

這是最簡單的一個路由的實現(xiàn)蚌吸。在實際的開發(fā)中,一般來講我們會在上方或左側(cè)簡歷導航欄砌庄,通過給導航欄元素添加<Link>來加載頁面剩下的內(nèi)容羹唠。聽起來有點像iframe?但是路由切換不會像iframe一樣直接加載一個頁面進來娄昆,只是通過路徑匹配組件的切換佩微。
當然,實際的開發(fā)中我們也不會這么不規(guī)范的直接把路由都寫在首頁里萌焰,一般會單寫一個router.js專門負責路由的控制哺眯。在后面的Dva框架中,我們會看到Dva把路由扒俯、公用組件奶卓、模型文件、服務文件等在創(chuàng)建工程時就幫我們分類好了撼玄,這樣整個工程結(jié)構(gòu)就非常清晰夺姑。

六.Redux管理狀態(tài)

在前一篇中我們說了,state是react特有的一個存儲數(shù)據(jù)的地方掌猛,我們通過各種操作可以改變state的值瑟幕,然后更新到頁面顯示上。
但是,當工程變得非常龐大且復雜的時候只盹,各種各樣的state和更新state的方法就會使程序變得很亂辣往。在我們后臺開發(fā)的時候,一向很講究邏輯對不對殖卑,而前后端分離的情況下站削,管理前端這些數(shù)據(jù),我們也需要進行“有條理的對數(shù)據(jù)進行操作”孵稽。
而進行這個操作的许起,就是Redux
Redux提供一些api來管理數(shù)據(jù)菩鲜,Redux很霸道地告訴我們:數(shù)據(jù)只能存在我這园细,并且只能通過我的方式來修改!
它包括三部分:store接校,action猛频,reducer

  1. store是一個……規(guī)范的state蛛勉,就像一個有條理的數(shù)據(jù)庫鹿寻,Redux將整個應用的state儲存在唯一的store中。
  2. action是……一個有屬性的對象诽凌,或者說描述了發(fā)生了什么的對象毡熏,用dispatch(action)來觸發(fā),并且這是改變state的唯一方式侣诵。
  3. reducer是……具體通過action更新state的那個函數(shù)痢法,基本結(jié)構(gòu)是,reducer(state, action) => newstate

簡單地講杜顺,state是雞翅财搁,action是烤熟了的雞翅,reducer是烤哑舒!

(好了妇拯,作為一個邏輯思維為0數(shù)學從沒及過格的人,我們就了解到這吧……什么洗鸵,還是得實踐一下代碼嗎Σ(⊙▽⊙")我明明是個設計師啊……)


那么我們繼續(xù)回到上一篇的那個例子上越锈。比如我們有這樣一個表格,現(xiàn)在我們想用Redux的方式做一些更改膘滨。(用Antd生成列表請看上一篇)

例子.png

首先要用npm或者yarn裝上redux甘凭。

npm install --save redux

我們大致知道了要創(chuàng)建一個store,并且定義好action和reducer火邓,那么一步一步開始丹弱。
一. 創(chuàng)建store
第一步在app.js中德撬,引入redux包中的createStore()方法。

import { createStore } from 'redux';

然后躲胳,通過createStore(reducers[蜓洪,initialState])的方式來創(chuàng)建store,這個方法根據(jù) reducer生成store坯苹,并且只能通過此reducer來改變store中的狀態(tài)隆檀,第二個參數(shù)是可選的默認初始值。
注意粹湃,一個應用中我們只有一個store恐仑,存儲了全部數(shù)據(jù)狀態(tài),但是會有很多reducer为鳄,通過這些reducer合起來創(chuàng)建store需要用到combineReducers方法裳仆。
但是我現(xiàn)在只想做一個簡單操作,所以用一個reducer做例子孤钦。

//初始狀態(tài)
const initialState = {
    ……
    data: [{
        "key": "1",
        "name": "王大斌",
        "gender": "男"
      },{
        "key": "2",
        "name": "劉小洋",
        "gender": "男"
      }]
}
//創(chuàng)建reducer方法歧斟,先原封不動返回state
const myreducer = (state=initialState, action) => {
  return state;
}
//創(chuàng)建store存儲區(qū),它只能通過reducer作為參數(shù)來構(gòu)造
const store = createStore(myreducer);

這樣store就創(chuàng)好了司训,可以把store打印到控制臺看一下构捡。getState()是store的一個最常見api液南,用了獲取state的值壳猜。

console.log("initial state: ", store.getState());
store中的狀態(tài).png

Very well,接下來寫一個更新state的action滑凉。

二. 創(chuàng)建action
Action 是一個帶屬性的對象统扳,其屬性用type來定義,type是必填項畅姊,其他的還可以有附帶數(shù)據(jù)咒钟,一般寫在用payload里。

//創(chuàng)建描述性對象action
const myaction = {
  type: 'ADD_DATA',
  payload: {
        "key": "3",
        "name": "張胖卓",
        "gender": "男"
  }
};

上面已經(jīng)說過若未,修改state的唯一方法就是dispatch(action),那么現(xiàn)在我們就把這個action觸發(fā)一下。

store.dispatch(myaction);

如果是點擊一個按鈕觸發(fā)的話必逆,把dispatch放在onClick綁定的函數(shù)里就行幅垮。

//點擊按鈕觸發(fā)
const changeData = () => {
    store.dispatch(myaction);
}

class App extends Component {
    render() {
        return ( 
            <Button type="primary" onClick={changeData}>修改數(shù)據(jù)</Button>
            ……
        );
    }
}

三. 創(chuàng)建reducer
Store觸發(fā)了一個action,相當于store宣稱:“我要改變自己的state”隙疚,此時壤追,需要reducer來執(zhí)行這個過程。
Reducer的輸入?yún)?shù)是當前的state和收到的action供屉,他會返回一個新的 state行冰。注意在reducer中溺蕉,不能隨意更改參數(shù)或者加入隨機性的各種操作,也就是reducer輸入相同的話悼做,輸出也必定相同疯特。
我們修改剛剛的reducer如下。

//創(chuàng)建reducer方法
const myreducer = (state=initialState, action) => {
  switch (action.type) {
    case 'ADD_DATA':
        return {
            ...state,
            data:state.data.concat(action.payload)
          }
    default: 
        return state;
  }
}

...state是ES6中的三點運算符肛走,作用是把數(shù)組打開進行操作辙芍。
可以看到,當action是ADD_DATA的時候羹与,我們把payload里面的內(nèi)容加在原有的data之后故硅,也就是新加一行數(shù)據(jù)。
這時纵搁,在控制臺輸出store的值吃衅,可以看到已經(jīng)有所改變。

console.log("change state: ", store.getState());
更新后的store.png

四. 通過監(jiān)聽更新視圖
然而腾誉,現(xiàn)在視圖上卻沒有刷新徘层,只是store中的值改變了。(這個問題糾結(jié)了我兩天= =)是因為store跟view層并沒有連起來利职,如果不手動重新render趣效,頁面是不會變化的,為此我們需要一個監(jiān)聽函數(shù)猪贪,監(jiān)聽store中值的變化跷敬,當發(fā)生變化時重新渲染view。
這個監(jiān)聽由store.subscribe實現(xiàn)热押。(如果你用了react-redux的話西傀,它里面的connect讓我們不需要自己手動去subscribe全局state的變化,它會在內(nèi)部自動監(jiān)聽并更新桶癣。)

class App extends Component {
    listerner() {
      let newState = store.getState();
      this.setState(newState);   
    }
    //保持監(jiān)聽
    componentDidMount () {
        store.subscribe(this.listerner.bind(this));
    }
}

這樣拥褂,整個流程實現(xiàn)了:

  1. 創(chuàng)建store存儲數(shù)據(jù),并把初始值綁定到view層牙寞。
  2. 點擊按鈕饺鹃,觸發(fā)store.dispatch(myaction)
  3. store收到action后间雀,調(diào)用myreducer = (state=initialState, action)改變store中的state悔详。
  4. store更新后,通過store.subscribe監(jiān)聽函數(shù)更新view層雷蹂。

最終的成果如下:

最終效果.png

ヽ(??▽?)ノ雖然很混亂不過總算似乎是實現(xiàn)了整套流程伟端。

【很重要的補充說明!】

在上面的例子里匪煌,我們只用了redux责蝠,事實上在React中党巾,我們一般常用react-redux來進行操作。react-redux提供的結(jié)構(gòu)可以讓我們不需要自己手動去寫dispatch霜医,subscribe這些函數(shù)齿拂,它在內(nèi)部通過自身的結(jié)構(gòu)幫我們完成了這些操作。
Dva肴敛,(終于說到了DvaJ鸷!),它已經(jīng)封裝好了react-router医男,react-redux砸狞,redux-saga等中間件,并給出了清晰地工程目錄結(jié)構(gòu)镀梭。因而在了解react基礎知識后刀森,用Dva來構(gòu)建工程更加快捷簡便。
那么报账,下一篇研底,我們就來真正用Dva創(chuàng)建一個工程并進行一些簡單操作~
請戳React爬坑之路三:Dva

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市透罢,隨后出現(xiàn)的幾起案子榜晦,更是在濱河造成了極大的恐慌,老刑警劉巖羽圃,帶你破解...
    沈念sama閱讀 222,865評論 6 518
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乾胶,死亡現(xiàn)場離奇詭異,居然都是意外死亡统屈,警方通過查閱死者的電腦和手機胚吁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,296評論 3 399
  • 文/潘曉璐 我一進店門牙躺,熙熙樓的掌柜王于貴愁眉苦臉地迎上來愁憔,“玉大人,你說我怎么就攤上這事孽拷《终疲” “怎么了?”我有些...
    開封第一講書人閱讀 169,631評論 0 364
  • 文/不壞的土叔 我叫張陵脓恕,是天一觀的道長膜宋。 經(jīng)常有香客問我,道長炼幔,這世上最難降的妖魔是什么秋茫? 我笑而不...
    開封第一講書人閱讀 60,199評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮乃秀,結(jié)果婚禮上肛著,老公的妹妹穿的比我還像新娘圆兵。我一直安慰自己,他們只是感情好枢贿,可當我...
    茶點故事閱讀 69,196評論 6 398
  • 文/花漫 我一把揭開白布殉农。 她就那樣靜靜地躺著,像睡著了一般局荚。 火紅的嫁衣襯著肌膚如雪超凳。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,793評論 1 314
  • 那天耀态,我揣著相機與錄音轮傍,去河邊找鬼。 笑死首装,一個胖子當著我的面吹牛金麸,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播簿盅,決...
    沈念sama閱讀 41,221評論 3 423
  • 文/蒼蘭香墨 我猛地睜開眼挥下,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了桨醋?” 一聲冷哼從身側(cè)響起棚瘟,我...
    開封第一講書人閱讀 40,174評論 0 277
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎喜最,沒想到半個月后偎蘸,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,699評論 1 320
  • 正文 獨居荒郊野嶺守林人離奇死亡瞬内,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,770評論 3 343
  • 正文 我和宋清朗相戀三年迷雪,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片虫蝶。...
    茶點故事閱讀 40,918評論 1 353
  • 序言:一個原本活蹦亂跳的男人離奇死亡章咧,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出能真,到底是詐尸還是另有隱情赁严,我是刑警寧澤,帶...
    沈念sama閱讀 36,573評論 5 351
  • 正文 年R本政府宣布粉铐,位于F島的核電站疼约,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏蝙泼。R本人自食惡果不足惜程剥,卻給世界環(huán)境...
    茶點故事閱讀 42,255評論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望汤踏。 院中可真熱鬧织鲸,春花似錦哨免、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,749評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至盾饮,卻和暖如春采桃,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背丘损。 一陣腳步聲響...
    開封第一講書人閱讀 33,862評論 1 274
  • 我被黑心中介騙來泰國打工普办, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人徘钥。 一個月前我還...
    沈念sama閱讀 49,364評論 3 379
  • 正文 我出身青樓衔蹲,卻偏偏與公主長得像,于是被迫代替她去往敵國和親呈础。 傳聞我的和親對象是個殘疾皇子舆驶,可洞房花燭夜當晚...
    茶點故事閱讀 45,926評論 2 361

推薦閱讀更多精彩內(nèi)容

  • 本文將開始詳細分析如何搭建一個React應用架構(gòu)。 一. 前言 現(xiàn)在已經(jīng)有很多腳手架工具而钞,如create-reac...
    字節(jié)跳動技術(shù)團隊閱讀 4,357評論 1 23
  • 做React需要會什么臼节? react的功能其實很單一撬陵,主要負責渲染的功能,現(xiàn)有的框架网缝,比如angular是一個大而...
    蒼都閱讀 14,769評論 1 139
  • 技術(shù)棧: react + redux + webpack + react-router + ES6/7/8 + i...
    黃昏少年閱讀 3,079評論 0 19
  • 004 同學見面 從派出所出去巨税,天還在下雨,漆黑的長街空無一人粉臊。慕容白害怕被再次抓進派出所草添,他冒雨去了...
    不可芳物閱讀 228評論 0 0
  • 從現(xiàn)在起,我開始謹慎地選擇我的生活维费,我不再輕易讓自己迷失在各種誘惑里果元。我心中已經(jīng)聽到來自遠方的呼喚,再不需要回過頭...
    菠菜黃閱讀 497評論 0 0