
ReactNative整理:《ReactNative系列》
內(nèi)容目錄
一、簡(jiǎn)介
二、Redux使用場(chǎng)景
三、Redux組成部分
???3.1 Action
???3.2 Reducer
???3.3 Store
四、React-Redux介紹
???4.1 React-Redux 組件分離思想
???4.2 connect 方法
???4.3 Provider
五、簡(jiǎn)單示例
一、簡(jiǎn)介
- 什么是
Redux
?Redux是 JavaScript 狀態(tài)容器,提供可預(yù)測(cè)化的狀態(tài)管理。對(duì)可預(yù)測(cè)化的個(gè)人理解:每個(gè)狀態(tài)都是由action觸發(fā)舊state更新生成新的state,生成結(jié)果可控,并且來源都只有一個(gè) -- store,所以是可預(yù)測(cè)的。
- 為什么要用
Redux
?通俗來講:由于多個(gè)路由頁(yè)面或組件之間消息傳遞或相互狀態(tài)控制太過繁瑣,需要中間頁(yè)面?zhèn)鬟f消息,通過props和state流經(jīng)多個(gè)組件來實(shí)現(xiàn)。這樣會(huì)使通信出錯(cuò)的概率大增,頁(yè)面越復(fù)雜交互越多,這種情況就越嚴(yán)重,所以需要一個(gè)可以統(tǒng)籌全局?jǐn)?shù)據(jù)狀態(tài)的工具,用作接收與分發(fā),這時(shí)就需要用到Redux。
從網(wǎng)上找到張圖片,可以形象的表示Redux的功能。

-
Redux的三大原則
Redux的使用需要遵循三大原則,這里先簡(jiǎn)單介紹,下文會(huì)詳細(xì)解釋。
1、單一數(shù)據(jù)源
?redux的數(shù)據(jù)都存放在store中,保證數(shù)據(jù)來源的唯一性,同時(shí)更便于應(yīng)用的數(shù)據(jù)交互;
2、state是只讀狀態(tài)
?action可以去取state的值,但是不能直接對(duì)state進(jìn)行修改;
3、使用純函數(shù)修改state
?利用reducer改變?cè)械膕tate狀態(tài),并生成一個(gè)新的state返回
Redux文檔:Redux文檔地址
二、Redux使用場(chǎng)景
首先,我們需要明確:Redux是很有用的框架,但并不是非用不可。
什么場(chǎng)景下可以不用:
- 用戶使用方式簡(jiǎn)單,沒有太過復(fù)雜的交互(這個(gè)就不用多解釋了)
- 數(shù)據(jù)來源單一:比方說,數(shù)據(jù)都是由父組件傳遞過來,只在當(dāng)前組件中使用;或者是從服務(wù)端拉取,同樣只在當(dāng)前組件中使用。
- 不需要大量與服務(wù)器交互
上面情況都可以不用Redux,那么與之相反的情況下就需要用到Redux了。
什么情況下使用:
- 用戶使用方式復(fù)雜 -- 交互頻繁且業(yè)務(wù)邏輯復(fù)雜
- 多個(gè)用戶之間可以協(xié)作
- 與服務(wù)器大量交互
- View需要從多個(gè)來源獲取數(shù)據(jù)
在多交互多數(shù)據(jù)源邏輯復(fù)雜的情況下,才需要用到Redux;具體情況要根據(jù)自身需求確定。
三、Redux組成部分
Redux是由三個(gè)重要組成部分協(xié)同工作的。包括:action、reducer和store。
3.1 Action
Action就是一個(gè)普通Object。其中type屬性是必須包含的,用來區(qū)分action或表示action的名字。其余屬性可以自行配置。Action是View發(fā)出的通知。View與用戶發(fā)生交互會(huì)引起store中state的改變,但是用戶不能直接操作state,只能看到或接觸到View層,所以需要在操作View的時(shí)候通知state發(fā)生改變,此時(shí)就要用到action。我們可以把action當(dāng)成是狀態(tài)存儲(chǔ)器store中狀態(tài)更新的觸發(fā)器。
const kAction_Add = {
type: 'Action_Add',
info: 'Todo_add'
}
如上:Action的名稱為Action_Add,跟隨該Action攜帶的信息為info,值為Todo_add,將整個(gè)對(duì)象定義為常量,命名為kAction_Add。
- View會(huì)發(fā)送很多種消息,因此就會(huì)有很多種Action,或者是同一種Action,但是攜帶的信息不同。我們不可能都手寫成常量,所以就會(huì)想到用函數(shù)的方式來生成Action,這就是Action Creator。
const kAction_Update = 'kAction_Update';
export function update(info) {
return {
type: kAction_Update,
info
}
}
const updateAction = update('information');
上面例子中:定義常量kAction_Update代表Action的名稱,應(yīng)用中Action種類比較多的時(shí)候可以將常量統(tǒng)一用一個(gè)常量JS文件管理,并導(dǎo)出方便引用。聲明方法update(info),可能沒接觸過React或JS的同學(xué)比較困惑對(duì)象中info是什么意思,這里代表的含義是info: info,前一個(gè)info是key值,后一個(gè)info是方法傳進(jìn)來的參數(shù)。
- 明白了Action的創(chuàng)建之后,就需要了解Action的發(fā)送。
store.dispatch()是View發(fā)出Action的唯一方式。
import { createStore } from 'redux';
// 這里的 func 是指函數(shù) -- reducer
const store = createStore(func);
store.dispatch({ type: 'kAction_Update', info: 'information'})
結(jié)合上面的代碼可以寫成:
store.dispatch(update('information'));
3.2 Reducer
View發(fā)送
action到store,引起了state的改變,使得View發(fā)生改變。那么action是如何鏈接到store中狀態(tài)的,又是如何引起狀態(tài)改變的?這就用到了reducer。我們可以將reducer看作是action和store之間的紐帶。Reducer是一個(gè)函數(shù),它需要兩個(gè)參數(shù):一個(gè)是默認(rèn)的state;另一個(gè)是action。最終經(jīng)過reducer處理過后會(huì)返回一個(gè)新的state。
import { combineReducers } from 'redux';
import * as Types from '../constants/type';
const initState = {
info: ''
};
function handleAction(state = initState, action) {
switch (action.type) {
case Types.kAction_Update:
return {
...state,
info: 'new' + action.info
};
case Types.kAction_Add:
return {
...state,
todo: 'new' + action.todo
};
default:
return state;
}
}
// handleAction 是一個(gè) Reducer 函數(shù),可以有多個(gè)類似handleAction這樣的 Reducer 函數(shù),用 combineReducers 整合成一個(gè)大的 Reducer
export default combineReducers({
handleAction
});
-
Redux提供combineReducers方法,用來將Reducer拆分。可以定義多個(gè)Reducer函數(shù),最終用該方法將它們組合成一個(gè)大的Reducer。 - 由于
Reducer是純函數(shù),函數(shù)的返回結(jié)果是由action和state決定的。正是Reducer這個(gè)特性決定了函數(shù)中不能修改state,只能返回一個(gè)全新對(duì)象。
Q:什么是純函數(shù)?
A:純函數(shù)是函數(shù)式編程的概念,需要滿足以下約束條件:
??1. 不得改寫參數(shù)
??2. 不能調(diào)用系統(tǒng) I/O 的 API
??3. 不能調(diào)用Data.now()或Math.random()等不純的方法,因?yàn)槊看蔚玫降慕Y(jié)果不一樣
3.3 Store
-
Store是存儲(chǔ)數(shù)據(jù)的地方,一個(gè)應(yīng)用只能有一個(gè)store。我們可以把它看成是浮在所有頁(yè)面之上的一個(gè)數(shù)據(jù)存儲(chǔ)容器,不同的組件和頁(yè)面都可以從這個(gè)容器中拿到需要的數(shù)據(jù)。 - Redux提供
createStore函數(shù)來生成store。
import { createStore } from 'redux';
import Reducers from '../reducers/commonReducer';
const commonStore = createStore(Reducers);
會(huì)接收一個(gè)Reducer作為參數(shù),返回生成的Store對(duì)象。
Store有以下職責(zé):
-
store.getState()方法獲取state; -
store.dispatch(action)方法更新state; -
store.subscribe(listener)注冊(cè)狀態(tài)監(jiān)聽器; -
store.subscribe(listener)返回的函數(shù)注銷監(jiān)聽器。
-
Store允許使用store.subscribe方法設(shè)置監(jiān)聽函數(shù),一旦state發(fā)生變化,就自動(dòng)執(zhí)行這個(gè)函數(shù)。
import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(listener);
store.subscribe方法返回一個(gè)函數(shù),調(diào)用這個(gè)函數(shù)就可以解除監(jiān)聽。
let unsubscribe = store.subscribe(() =>
console.log(store.getState())
);
unsubscribe();
四、React-Redux介紹
React和Redux原本是兩個(gè)相互獨(dú)立的框架,為了使用起來更高效更靈活,Redux官方針對(duì)React封裝了一套數(shù)據(jù)狀態(tài)管理框架 -- React-Redux。
4.1 React-Redux 組件分離思想
?React-Redux涉及到容器組件和展示組件分離的思想,在React-Redux中將組件分為 UI組件 和 容器組件
- UI組件
什么是UI組件?可以理解為只負(fù)責(zé)頁(yè)面顯示。UI組件有如下特征:
1、只負(fù)責(zé)UI呈現(xiàn),不包含任何邏輯處理;
2、沒有狀態(tài)(即不使用this.state);
3、所有數(shù)據(jù)都由props提供;
4、不使用Redux的API。
- 容器組件
容器組件包含以下特征:
1、負(fù)責(zé)數(shù)據(jù)處理和業(yè)務(wù)邏輯;
2、包含內(nèi)部狀態(tài);
3、會(huì)使用Redux的API。
可能很多人比較困惑:我們自己寫的組件里面也有很多業(yè)務(wù)邏輯和數(shù)據(jù)處理,難道要都拆開嗎?其實(shí)不用,React-Redux規(guī)定,UI組件由用戶提供,容器組件由 React-Redux 自動(dòng)生成。
我們可以理解為用戶自己創(chuàng)建的組件都是UI組件,和React-Redux生成的容器組件是互不干擾的,它能提供組件,使整個(gè)應(yīng)用可以訪問到Redux Store。
4.2 connect 方法
React-Redux提供connect方法,用于從UI組件生成容器組件;該方法不會(huì)改變用戶創(chuàng)建的組件,而是返回新的已與 Redux store 連接之后生成的 connect 過的組件。
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
connect可以有四個(gè)參數(shù),但是常用的只有前兩個(gè)mapStateToProps,mapDispatchToProps。
- mapStateToProps(state, [ownProps]): stateProps
mapStateToProps:從字面意思也可以理解,該函數(shù)的作用就是建立從(外部的)state到UI組件的props的映射關(guān)系。定義該參數(shù),組件就會(huì)監(jiān)聽 Redux Store 的數(shù)據(jù)變化,只要 Store 中對(duì)應(yīng)數(shù)據(jù)發(fā)生變化,就會(huì)調(diào)用該函數(shù),函數(shù)中的對(duì)象會(huì)與組件的props合并。如果指定了該回調(diào)函數(shù)中的第二個(gè)參數(shù) ownProps,則該參數(shù)的值為傳遞到組件的 props,而且只要組件接收到新的 props(例如:父組件中參數(shù)修改導(dǎo)致當(dāng)前組件props變動(dòng)),mapStateToProps 也會(huì)被調(diào)用。
const mapStateToProps = (state, ownProps) => {
return {
count: state.counter.count,
imageUrl: state.load.imageUrl === ownProps.imageUrl
}
}
- mapDispatchToProps(dispatch, [ownProps]): dispatchProps
mapDispatchToProps:是connect的第二個(gè)參數(shù),作用是用來建立UI組件和store.dispatch之間的映射。如果傳遞的參數(shù)是一個(gè)對(duì)象,那么每個(gè)定義在該對(duì)象中的函數(shù)都會(huì)被當(dāng)作Action Creator;
函數(shù)寫法舉例:
/**
* 各個(gè)Action可以分開表示
* 需要用到 redux 中的方法 bindActionCreators 將 dipstch 與自定義action綁定到一起
* reduceCount 和 increaseCount 為action對(duì)應(yīng)的屬性值,使用時(shí)
* 只需要調(diào)用 this.props.reduceCount 或 this.props.increaseCount 即可
*/
const mapDispatchToProps = dispatch => ({
reduceCount: bindActionCreators(countReduceAction, dispatch),
increaseCount: bindActionCreators(countIncreaseAction, dispatch)
})
/**
* action統(tǒng)一用 dispatch 發(fā)送
* 使用時(shí),調(diào)用 this.props.dispatch(自定義action creator)
*/
const mapDispatchToProps = dispatch => ({
dispatch
})
/**
* 將所有action組合成一個(gè)大的 action creator 對(duì)象
* actions 為組合后的對(duì)象屬性key
* 使用時(shí),調(diào)用 this.props.actions.countReduceAction() 或 this.props.actions.countIncreaseAction()
*/
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(Object.assign({}, {
countReduceAction,
countIncreaseAction
}, ), dispatch)
})
- mergeProps(stateProps, dispatchProps, ownProps): props
mergeProps函數(shù)會(huì)將前兩個(gè)參數(shù)mapStateToProps和mapDispatchToProps的執(zhí)行結(jié)果和組件自身的props傳入到該回調(diào)函數(shù)中,有特殊數(shù)據(jù)需要處理的可以在該方法里處理,函數(shù)的返回結(jié)果將會(huì)作為props傳遞到包裝過的組件中,一般情況下可以不用傳。
- options
如果指定該參數(shù),可以定制connector的行為?;静挥茫肓私獾目梢匀ゲ榭?code>redux文檔。
4.3 Provider
<Provider store>可以使組件層級(jí)中的所有connect方法,都能夠鏈接到Redux Store。一般情況下需要將根組件嵌套在<Provider>中才能使用connect方法。
render() {
return (
<Provider store={this.state.store}>
<SwitchConstruct
onNavigationStateChange={this.handleNavigationChange}
/>
</Provider>
);
}
五、簡(jiǎn)單示例
1、首先創(chuàng)建Action Creators,將action的標(biāo)識(shí)統(tǒng)一用一個(gè)文件管理
import * as Types from '../../constant/types';
export function countReduceAction(count) {
return {
type: Types.kCount_Reduce,
count
}
}
export function countIncreaseAction(count) {
return {
type: Types.kCount_Increase,
count
}
}
2、創(chuàng)建Reducer,注意需要有初始化數(shù)據(jù);多個(gè)Reducer的情況下可以用combineReducers方法合并成一個(gè)大的Reducers。
/**
* 計(jì)數(shù)reducer
*/
import * as Types from '../../constant/types';
const countInitReduce = {
count: -1
}
export default function handleCount(state = countInitReduce, action) {
switch (action.type) {
case Types.kCount_Reduce:
return {
...state,
count: action.count - 1
};
case Types.kCount_Increase:
return {
...state,
count: action.count + 1
};
default:
return state;
}
}
import { combineReducers } from 'redux';
import handleCount from './countReducer';
import handleLoadImage from './loadImageReducer';
/**
* reducers組合返回
*/
const reducers = combineReducers({
countStore: handleCount,
loadImageStore: handleLoadImage
});
export default reducers;
3、生成Store,存儲(chǔ)全局狀態(tài)數(shù)據(jù)
import reducers from '../reducers/baseReducer';
import { createStore } from 'redux';
export function configStore() {
const store = createStore(reducers);
return {
store
};
}
4、用Provider包裹根組件,并將其connect到組件中,這樣在組件中就可以調(diào)用action了。
const mapStateToProps = (state) => ({
count: state.countStore.count,
imageUrl: state.loadImageStore.imageUrl
});
const mapDispatchToProps = dispatch => ({
dispatch
})
export default connect(mapStateToProps, mapDispatchToProps)(HomeClass);
?以上就是Redux和React-Redux的理解和簡(jiǎn)單使用,有問題的地方歡迎指出,喜歡的話可以點(diǎn)贊關(guān)注。