React爬坑之路二:Router+Redux
上一篇寫了Antd和Axios的基本操作
之前大標(biāo)題到五了那么這篇從六開始
ST也是初學(xué)小白可能講的完全不對
大家當(dāng)做小說隨便讀讀消遣一下就好
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配置路由
在實(shí)際應(yīng)用中,我們不可能只有一頁頁面,切換頁面需要通過Router配置,這樣輸入不同的url就能看到不同的頁,或者點(diǎn)擊不同的按鈕可以在下方加載不同的組件。
(這里補(bǔ)充一下組件的概念,其實(shí)其本質(zhì)就是一個(gè)類。在頁面中我們可以把頁面分為導(dǎo)航區(qū),側(cè)邊欄,工作區(qū)等不同區(qū)域,每個(gè)區(qū)域都是一個(gè)組件,組件中還可以繼續(xù)細(xì)分為其他組件。想象在創(chuàng)建頁面的時(shí)候把不同的組件拿來組合在一起,頁頭頁尾這種公用組件可以始終保持不動,只切換我們想切換的區(qū)域。)
一般來講,我們用React-router-dom來實(shí)現(xiàn),它提供了BrowserRouter, Route, Link等api,讓我們可以通過dom事件控制路由。
第一步還是安裝。
npm install react-router-dom --save
這時(shí)我們新建兩個(gè)組件aaa.js和bbb.js。
import React, { Component } from ‘react’;
class AAA extends Component {
render() {
return (
AAA
)
}
}
export default AAA;
import React, { Component } from ‘react’;
class BBB extends Component {
render() {
return (
BBB
)
}
}
export default BBB;
并且在首頁上搞兩個(gè)按鈕。(不會搞的請去看上一篇)
假裝是導(dǎo)航.png
然后,將剛剛的兩個(gè)組件,和React-router-dom中的一些api導(dǎo)入首頁app.js。這里我們用了BrowserRouter,當(dāng)然也可以用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都需要寫在里
此時(shí)點(diǎn)擊按鈕可以看到地址欄是改變的,會變成http://localhost:3000/aaa和http://localhost:3000/bbb。
然后,在下方加上要通過路由切換的組件,當(dāng)path為aaa或者bbb的時(shí)候分別加載AAA和BBB。
此時(shí),在瀏覽器中點(diǎn)擊兩個(gè)按鈕,應(yīng)該能看到下方可以切換兩種組件啦。
AAA.png
BBB.png
這是最簡單的一個(gè)路由的實(shí)現(xiàn)。在實(shí)際的開發(fā)中,一般來講我們會在上方或左側(cè)簡歷導(dǎo)航欄,通過給導(dǎo)航欄元素添加來加載頁面剩下的內(nèi)容。聽起來有點(diǎn)像iframe?但是路由切換不會像iframe一樣直接加載一個(gè)頁面進(jìn)來,只是通過路徑匹配組件的切換。
當(dāng)然,實(shí)際的開發(fā)中我們也不會這么不規(guī)范的直接把路由都寫在首頁里,一般會單寫一個(gè)router.js專門負(fù)責(zé)路由的控制。在后面的Dva框架中,我們會看到Dva把路由、公用組件、模型文件、服務(wù)文件等在創(chuàng)建工程時(shí)就幫我們分類好了,這樣整個(gè)工程結(jié)構(gòu)就非常清晰。
六.Redux管理狀態(tài)
在前一篇中我們說了,state是react特有的一個(gè)存儲數(shù)據(jù)的地方,我們通過各種操作可以改變state的值,然后更新到頁面顯示上。
但是,當(dāng)工程變得非常龐大且復(fù)雜的時(shí)候,各種各樣的state和更新state的方法就會使程序變得很亂。在我們后臺開發(fā)的時(shí)候,一向很講究邏輯對不對,而前后端分離的情況下,管理前端這些數(shù)據(jù),我們也需要進(jìn)行“有條理的對數(shù)據(jù)進(jìn)行操作”。
而進(jìn)行這個(gè)操作的,就是Redux。
Redux提供一些api來管理數(shù)據(jù),Redux很霸道地告訴我們:數(shù)據(jù)只能存在我這,并且只能通過我的方式來修改!
它包括三部分:store,action,reducer。
store是一個(gè)……規(guī)范的state,就像一個(gè)有條理的數(shù)據(jù)庫,Redux將整個(gè)應(yīng)用的state儲存在唯一的store中。
action是……一個(gè)有屬性的對象,或者說描述了發(fā)生了什么的對象,用dispatch(action)來觸發(fā),并且這是改變state的唯一方式。
reducer是……具體通過action更新state的那個(gè)函數(shù),基本結(jié)構(gòu)是,reducer(state, action) => newstate
簡單地講,state是雞翅,action是烤熟了的雞翅,reducer是烤!
(好了,作為一個(gè)邏輯思維為0數(shù)學(xué)從沒及過格的人,我們就了解到這吧……什么,還是得實(shí)踐一下代碼嗎Σ(⊙▽⊙")我明明是個(gè)設(shè)計(jì)師啊……)
那么我們繼續(xù)回到上一篇的那個(gè)例子上。比如我們有這樣一個(gè)表格,現(xiàn)在我們想用Redux的方式做一些更改。(用Antd生成列表請看上一篇)
例子.png
首先要用npm或者yarn裝上redux。
npm install --save redux
我們大致知道了要?jiǎng)?chuàng)建一個(gè)store,并且定義好action和reducer,那么一步一步開始。
一. 創(chuàng)建store
第一步在app.js中,引入redux包中的createStore()方法。
import { createStore } from ‘redux’;
然后,通過createStore(reducers[,initialState])的方式來創(chuàng)建store,這個(gè)方法根據(jù) reducer生成store,并且只能通過此reducer來改變store中的狀態(tài),第二個(gè)參數(shù)是可選的默認(rèn)初始值。
注意,一個(gè)應(yīng)用中我們只有一個(gè)store,存儲了全部數(shù)據(jù)狀態(tài),但是會有很多reducer,通過這些reducer合起來創(chuàng)建store需要用到combineReducers方法。
但是我現(xiàn)在只想做一個(gè)簡單操作,所以用一個(gè)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的一個(gè)最常見api,用了獲取state的值。
console.log("initial state: ", store.getState());
store中的狀態(tài).png
Very well,接下來寫一個(gè)更新state的action。
二. 創(chuàng)建action
Action 是一個(gè)帶屬性的對象,其屬性用type來定義,type是必填項(xiàng),其他的還可以有附帶數(shù)據(jù),一般寫在用payload里。
//創(chuàng)建描述性對象action
const myaction = {
type: ‘ADD_DATA’,
payload: {
“key”: “3”,
“name”: “張胖卓”,
“gender”: “男”
}
};
上面已經(jīng)說過,修改state的唯一方法就是dispatch(action),那么現(xiàn)在我們就把這個(gè)action觸發(fā)一下。
store.dispatch(myaction);
如果是點(diǎn)擊一個(gè)按鈕觸發(fā)的話,把dispatch放在onClick綁定的函數(shù)里就行。
//點(diǎn)擊按鈕觸發(fā)
const changeData = () => {
store.dispatch(myaction);
}
class App extends Component {
render() {
return (
修改數(shù)據(jù)
……
);
}
}
三. 創(chuàng)建reducer
Store觸發(fā)了一個(gè)action,相當(dāng)于store宣稱:“我要改變自己的state”,此時(shí),需要reducer來執(zhí)行這個(gè)過程。
Reducer的輸入?yún)?shù)是當(dāng)前的state和收到的action,他會返回一個(gè)新的 state。注意在reducer中,不能隨意更改參數(shù)或者加入隨機(jī)性的各種操作,也就是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中的三點(diǎn)運(yùn)算符,作用是把數(shù)組打開進(jìn)行操作。
可以看到,當(dāng)action是ADD_DATA的時(shí)候,我們把payload里面的內(nèi)容加在原有的data之后,也就是新加一行數(shù)據(jù)。
這時(shí),在控制臺輸出store的值,可以看到已經(jīng)有所改變。
console.log("change state: ", store.getState());
更新后的store.png
四. 通過監(jiān)聽更新視圖
然而,現(xiàn)在視圖上卻沒有刷新,只是store中的值改變了。(這個(gè)問題糾結(jié)了我兩天= =)是因?yàn)閟tore跟view層并沒有連起來,如果不手動重新render,頁面是不會變化的,為此我們需要一個(gè)監(jiān)聽函數(shù),監(jiān)聽store中值的變化,當(dāng)發(fā)生變化時(shí)重新渲染view。
這個(gè)監(jiān)聽由store.subscribe實(shí)現(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));
}
}
這樣,整個(gè)流程實(shí)現(xiàn)了:
創(chuàng)建store存儲數(shù)據(jù),并把初始值綁定到view層。
點(diǎn)擊按鈕,觸發(fā)store.dispatch(myaction)。
store收到action后,調(diào)用myreducer = (state=initialState, action)改變store中的state。
store更新后,通過store.subscribe監(jiān)聽函數(shù)更新view層。
最終的成果如下:
最終效果.png
ヽ(?゚▽゚)ノ雖然很混亂不過總算似乎是實(shí)現(xiàn)了整套流程。
【很重要的補(bǔ)充說明!】
在上面的例子里,我們只用了redux,事實(shí)上在React中,我們一般常用react-redux來進(jìn)行操作。react-redux提供的結(jié)構(gòu)可以讓我們不需要自己手動去寫dispatch,subscribe這些函數(shù),它在內(nèi)部通過自身的結(jié)構(gòu)幫我們完成了這些操作。
而Dva,(終于說到了Dva!),它已經(jīng)封裝好了react-router,react-redux,redux-saga等中間件,并給出了清晰地工程目錄結(jié)構(gòu)。因而在了解react基礎(chǔ)知識后,用Dva來構(gòu)建工程更加快捷簡便。
那么,下一篇,我們就來真正用Dva創(chuàng)建一個(gè)工程并進(jìn)行一些簡單操作~
請戳React爬坑之路三:Dva
作者:saint37
鏈接:https://www.jianshu.com/p/dbf6dda29401
來源:簡書
著作權(quán)歸作者所有。商業(yè)轉(zhuǎn)載請聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請注明出處。
總結(jié)
以上是生活随笔為你收集整理的React爬坑之路二:Router+Redux的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 工信部191号文《App违法违规收集使用
- 下一篇: Python_Dataframe_去除重