React-redux

一通惫、認(rèn)識(shí)Redux

安裝

npm install --save redux?

npm install --save react-redux

一句話理解Redux

應(yīng)用中的所有state都以一個(gè)對象數(shù)樹的方式存儲(chǔ)在一個(gè)單一的store中搀军,唯一改變state的方法就是觸發(fā)action强缘,一個(gè)描述發(fā)生什么的對象片习,為了描述action如何改變state樹延届,需要編寫reducers址貌。

什么是Action脚翘?

Action本質(zhì)上是JavaScript的普通對象骂因,action內(nèi)必須使用一個(gè)字符串類型的type字段來表示將要執(zhí)行的動(dòng)作炎咖。多數(shù)情況下type會(huì)被定義成字符串常量。我們應(yīng)該盡量減少在actin中傳遞數(shù)據(jù)寒波。

Action:

export const ADD = 'ADD'

export const add = () => ({

? ?type: ADD

})


export const SUB = 'SUB'

export const sub = () => ({

? ?type: SUB

})

什么是Reducer乘盼?

設(shè)計(jì)state結(jié)構(gòu)

Action處理

reducer是一個(gè)純函數(shù),接受舊的state和action俄烁,返回新的state绸栅。

注意: 每個(gè) reducer 只負(fù)責(zé)管理全局 state 中它負(fù)責(zé)的一部分。每個(gè) reducer 的 state 參數(shù)都不同页屠,分別對應(yīng)它管理的那部分 state 數(shù)據(jù)粹胯。

Reducer:

import { ADD, SUB } from 'Action'


const counter = (state = 0, action) => {

? ?switch (action.type) {

? ? ? ?case ADD:

return state + 1

case SUB:

return state - 1

default:

return state

}

}

總結(jié):把要做的修改變成一個(gè)普通對象蓖柔,這個(gè)對象叫做action,而不是直接修改state风纠。然后編寫專門的函數(shù)來決定每個(gè)action如何改變應(yīng)用的state况鸣,這個(gè)函數(shù)叫做reducer。


二竹观、關(guān)于Redux的重點(diǎn)知識(shí)

1. 三大原則

(1)單一數(shù)據(jù)源

整個(gè)應(yīng)用的state被存儲(chǔ)在一棵object tree中镐捧,并且這個(gè)object tree只存在于唯一一個(gè)store中。

(2)state是只讀的

唯一改變state的方法就是觸發(fā)action臭增,action是一個(gè)用于描述已發(fā)生事件的普通對象懂酱。

(3)使用純函數(shù)來執(zhí)行修改

為了描述action如何改變state,需要寫reducers。

注意:永遠(yuǎn)不要在reducer中做這些操作

修改傳入?yún)?shù)誊抛;

執(zhí)行有副作用的操作列牺,如API請求和路由跳轉(zhuǎn);

調(diào)用非純函數(shù)芍锚,如Date.now(), Math.random()昔园。

只要傳入?yún)?shù)相同,返回計(jì)算得到的下一個(gè)state就一定相同并炮。沒有特殊情況默刚,沒有副作用,沒有API請求逃魄,沒有變量修改荤西,單純執(zhí)行計(jì)算。

2.combineReducer

為什么使用combineReducer?

隨著應(yīng)用變得復(fù)雜伍俘,需要對 reducer 函數(shù)進(jìn)行拆分邪锌,拆分后的每一塊獨(dú)立負(fù)責(zé)管理 state 的一部分。


combineReducers 輔助函數(shù)的作用是癌瘾,把一個(gè)由多個(gè)不同 reducer 函數(shù)作為 value 的 object觅丰,合并成一個(gè)最終的 reducer 函數(shù),然后就可以對這個(gè) reducer 調(diào)用 createStore妨退。


合并后的 reducer 可以調(diào)用各個(gè)子 reducer妇萄,并把它們的結(jié)果合并成一個(gè) state 對象。state 對象的結(jié)構(gòu)由傳入的多個(gè) reducer 的 key 決定咬荷。

import { combineReducer } from 'redux'


const todoApp = combineReducer({

? ?visibilityFilter,

? ?todos

})


export default todoApp

等價(jià)寫法 =>

export const todoApp = (state = {}, action) => {

? ?return {

? ? ? ?visibilityFilter: visibilityFilter(state.visibilityFilter, action)

? ? ? ?todos: todos(state.todos, action)

? ?}

}

conbineReducer所做的是生成一個(gè)函數(shù)冠句,這個(gè)函數(shù)來調(diào)用你的一系列reducer,每個(gè)reducer根據(jù)他的key來篩選出state中的一部分?jǐn)?shù)據(jù)并處理,然后這個(gè)生成的函數(shù)再將所有reducer的結(jié)果合并成一個(gè)大的對象幸乒。

combineReducer示例:

reducers/todos.js

export default function todos(state = [], action) {

?switch (action.type) {

?case 'ADD_TODO':

? ?return state.concat([action.text])

?default:

? ?return state

?}

}

reducers/counter.js

export default function counter(state = 0, action) {

?switch (action.type) {

?case 'INCREMENT':

? ?return state + 1

?case 'DECREMENT':

? ?return state - 1

?default:

? ?return state

?}

}

reducers/index.js

import { combineReducers } from 'redux'

import todos from './todos'

import counter from './counter'


export default combineReducers({

?todos,

?counter

})

App.js

import { createStore } from 'redux'

import reducer from './reducers/index'


let store = createStore(reducer)

3.Redux中的connect()方法

(1)定義mapStateToProps方法

把當(dāng)前Redux store state映射到展示組件的props中懦底。

(2)定義mapDispatchToProps方法

接收dispatch()方法并返回期望注入到展示組件的props中的回調(diào)方法。

import { connect } from 'react-redux'

import { Task } from './reducers'


const mapStateToProps = (state) => {

? ?return {

? ? ? ?tasks: state.entities.tasks

? ?}

}


const mapDispatchToProps = (dispatch) => {

? ?return {

? ? ? ?addUnit: (taskID, unitID, units) => {

? ? ? ? ? ?dispatch(Task.addUnit(taskID, unitID, units))

? ? ? ?}

? ?}

}


等價(jià)于 =>


const mapDispatchToProps = (dispatch) => {

? ?return {

? ? ? ?addUnit: (taskID, unitID, units) => Task.addUnit(taskID, unitID, units))

? ?}

}



//多個(gè)conncet的書寫方式

const VisibleCreateUnit = connect(

? ?mapStateToProps,

? ?mapDispatchToProps

)(CreateUnit)


const VisibleCreateTask = connect(

? ?mapStateToProps,

? ?mapDispatchToProps

)(CreateTask)


export { VisibleCreateUnit, VisibleCreateTask }

4.Store

(1)createStore()

createStore() 的第二個(gè)參數(shù)是可選的, 用于設(shè)置 state 初始狀態(tài)罕扎。這對開發(fā)同構(gòu)應(yīng)用時(shí)非常有用聚唐,服務(wù)器端 redux 應(yīng)用的 state 結(jié)構(gòu)可以與客戶端保持一致, 那么客戶端可以將從網(wǎng)絡(luò)接收到的服務(wù)端 state 直接用于本地?cái)?shù)據(jù)初始化丐重。

(2)Redux Provider

import { Provider } from 'react-redux'

import { createStore } from 'redux'

在React-router中使用Provider

const store = createStore(appReducer, normalizedState)









5.數(shù)據(jù)序列化(normalize)

示例:Tasks中包含subTasks和units,subTasks中又包含units。

import { normalize, schema } from 'normalizr'


//首先使用schema最小單元即units

const unitsSchema = new schema.Entity('units')

//subTasks中包含units

const subTasksSchema = new schema.Entity('subTasks', { units: [unitsSchema] })

//tasks中包含subTasks和units

const tasksSchema = new schema.Entity('tasks', {

subTasks: [subTasksSchema],

units: [unitsSchema]

})



......

const initialState = {

? ?tasks: {

? ? ? ?subTasks: {

? ? ? ? ? ?units: {

? ? ? ? ? ? ? ?......

? ? ? ? ? ?}

? ? ? ? ? ?......

? ? ? ?},

? ? ? ?units: {

? ? ? ? ? ?......

? ? ? ?}

? ?},

? ?groups: {

? ? ? ?......

? ?},

? ?classes: {

? ? ? ?......

? ?},

? ?rosters: {

? ? ? ?......

? ?}

}


const stateSchema = {

? ?tasks: [tasksSchema],

? ?groups: [groupsSchema],

? ?classes: [classesSchema],

? ?rosters: [rostersSchema]

}


const normalizedState = normalize(initialState, stateSchema)

console.log('normalizedState', normalizedState)


Object{

? ?entities: Object{

? ? ? ?.....

? ?}

? ?result: Object{

? ? ? ?tasks: array[2],

? ? ? ?groups: array[3],

? ? ? ?classes: array[4],

? ? ? ?rosters: array[5]

? ?}

}

注意:鍵一定與數(shù)組中的鍵一一對應(yīng)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末拱层,一起剝皮案震驚了整個(gè)濱河市弥臼,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌根灯,老刑警劉巖径缅,帶你破解...
    沈念sama閱讀 206,968評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異烙肺,居然都是意外死亡纳猪,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評論 2 382
  • 文/潘曉璐 我一進(jìn)店門桃笙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來氏堤,“玉大人,你說我怎么就攤上這事搏明∈笮猓” “怎么了?”我有些...
    開封第一講書人閱讀 153,220評論 0 344
  • 文/不壞的土叔 我叫張陵星著,是天一觀的道長购笆。 經(jīng)常有香客問我,道長虚循,這世上最難降的妖魔是什么同欠? 我笑而不...
    開封第一講書人閱讀 55,416評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮横缔,結(jié)果婚禮上铺遂,老公的妹妹穿的比我還像新娘。我一直安慰自己茎刚,他們只是感情好襟锐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著膛锭,像睡著了一般捌斧。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上泉沾,一...
    開封第一講書人閱讀 49,144評論 1 285
  • 那天,我揣著相機(jī)與錄音妇押,去河邊找鬼跷究。 笑死,一個(gè)胖子當(dāng)著我的面吹牛敲霍,可吹牛的內(nèi)容都是我干的俊马。 我是一名探鬼主播丁存,決...
    沈念sama閱讀 38,432評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼柴我!你這毒婦竟也來了解寝?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,088評論 0 261
  • 序言:老撾萬榮一對情侶失蹤艘儒,失蹤者是張志新(化名)和其女友劉穎聋伦,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體界睁,經(jīng)...
    沈念sama閱讀 43,586評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡觉增,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了翻斟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片逾礁。...
    茶點(diǎn)故事閱讀 38,137評論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖访惜,靈堂內(nèi)的尸體忽然破棺而出嘹履,到底是詐尸還是另有隱情,我是刑警寧澤债热,帶...
    沈念sama閱讀 33,783評論 4 324
  • 正文 年R本政府宣布砾嫉,位于F島的核電站,受9級特大地震影響阳柔,放射性物質(zhì)發(fā)生泄漏焰枢。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評論 3 307
  • 文/蒙蒙 一舌剂、第九天 我趴在偏房一處隱蔽的房頂上張望济锄。 院中可真熱鬧,春花似錦霍转、人聲如沸荐绝。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽低滩。三九已至,卻和暖如春岩喷,著一層夾襖步出監(jiān)牢的瞬間恕沫,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評論 1 262
  • 我被黑心中介騙來泰國打工纱意, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留婶溯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像迄委,于是被迫代替她去往敵國和親褐筛。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評論 2 345

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