Redux 單項數據流框架,其特色是嚴格的數據流控制,開發過程當中應遵循3個原則:react
Redux 應用中應保持數據源的惟一性,說白了整個應用中只保持一個 Store,全部組件的數據源就是這個 Store 上的狀態,Store 是個樹形結構,每每某一個組件或者模塊的數據來源於 Store 上的某個節點。git
Redux 強調要改變 Store 的狀態只能經過 action ,action 返回對象,提供給 Redux 完成新的狀態的組裝。github
這裏的純函數就是 Reducer ,其函數簽名包含兩個參數 state、action,顧名思義就是經過 action 去改變 state,通常來講是返回一個新的 state,其函數簽名大體以下export default (state = initialState, action) => {}
。redux
Reudx 包含 Store、State、Reudcer、action,主要爲這四部分組成:bash
{ type: actionType, data: ooxx };
這裏說一下 actionType:一個常亮,用來區分不一樣的 action所謂聰明、傻瓜只是相對來講,一樣也叫容器組件和展現組件。 鑑於專業性,下文一概採用容器組件和展現組件的叫法。容器組件負責將 Store 中的狀態,經過 props 傳遞給展現組件,展現組件只負責渲染頁面,無需持有狀態。將一個組件拆分爲容器組件和展現組件是設計 React 組件的一種模式,和 Redux 無關。框架
上面講到,Redux 負責管理狀態,組件拆分爲容器組件和展現組件。容器組件須要狀態,狀態來自哪呢?固然是 Redux 。 故,能夠將 Redux 和組件作一個結合,達到更好的效果,那就是 react-redux,他幫助開發者抽取了可複用的容器組件,開發者只需關注展現組件便可。 相比於 Redux ,react-redux 多了 Provider 和 connect 兩部分ide
理解 Provider 首先要知道 context ,也就是上下文。試想這樣一種業務場景:一個多層嵌套的組件結構中,只有最裏層的組件須要使用 store ,首先想到的是用 props 傳遞,爲了把 store 從最外層傳遞到最裏層,就要中間的全部組件都增長對 store的支持 ,這樣無疑是災難,很麻煩。React 提供了 context 的支持,就是說一個樹型結構中的全部組件都能訪問一個對象(上下文)。爲了讓樹形結構支持 context ,須要父組件聲明對 context 的支持, Provider 就提供了這樣的功能(也是一個組件,增長了 context)。因此咱們會看到 Provider 須要傳遞一個 store 屬性,而且位於根組件的位置,這樣應用中全部的組件都會經過 context 共享這個 store 。react-redux 提供了建立 Store 的方法。函數
一個函數,負責展現組件和容器組件的鏈接。大體是這樣export default connect(mapStateToProps, mapDispatchToProps)(SearchBar)
這裏邊實際上是兩次函數的執行,首先 connect 函數執行並返回了另外一個函數而後執行,參數是展現組件。flex
其實 connect
在執行的過程當中實際上產生了一個無名的 React 組件,這個組件定製了 shouldComponentUpdate
函數的實現,實現邏輯是比對此次傳遞給內層展現組件的 props 和上一次的 props ,由於負責「組件看起來怎樣」的展現組件是一個無狀態的組件,他的渲染徹底由傳入的 props 決定,若是 props 沒有變化,那就能夠認爲渲染結果確定同樣。就不須要通過 VirtualDOM 作渲染。ui
不難理解 react-redux 告訴咱們,展現組件僅僅負責展現,不須要持有任何狀態,展現組件的全部 state、action 所有來源於 props ,容器組件經過 props 傳遞給展現組件。
export const HOMEPAGE_SHOWSEARCHBAR = 'HOMEPAGE/SHOWSEARCHBAR';
export const HOMEPAGE_MENU_PAGECHANGE = 'HOMEPAGE/MENU/PAGECHANGE';
複製代碼
export const searchBarFetch = (text) => ({
type: HOMEPAGE_FETCH_SEARCHBAR,
text: text
});
export const updateHomePageMenuPage = (page) => ({
type: HOMEPAGE_MENU_PAGECHANGE,
currentPage: page
});
複製代碼
const initialState = {
homepage: {
menuInfo: {
items: common.menuInfos,
currentPage: 0
},
gridInfos: [],
sections: [{
title: '',
data: []
}],
},
searchBar: {
text: '搜一下'
}
};
複製代碼
export default (state = initialState, action) => {
switch (action.type) {
case HOMEPAGE_FETCH_SEARCHBAR:
{
return {
...state,
searchBar: {
text: action.text
}
};
}
case HOMEPAGE_MENU_PAGECHANGE:
{
return {
...state,
homepage: {
menuInfo: {
items: state.homepage.menuInfo.items,
currentPage: action.currentPage
},
gridInfos: state.homepage.gridInfos,
sections: state.homepage.sections
}
}
}
}
return state;
};
複製代碼
const reducers = combineReducers({
homepageReudcer
});
export default createStore(reducers);
複製代碼
class HomeMenu extends Component {
render() {
const {menuInfos, currentPage} = this.props;
const items = menuInfos.map(({title, icon}) => (<HomeMenuItem title={title} icon={icon} key={title}/>));
const pageCount = Math.ceil(items.length / 10);
let menuViews = [];
for (let i = 0; i < pageCount; i++) {
const itemSlices = items.slice(i * 10, i * 10 + 10);
const view = <View style={styles.itemsView} key={i}>
{itemSlices}
</View>
menuViews.push(view);
}
return (
<View style={styles.container}>
<ScrollView
horizontal
pagingEnabled={true}
showsHorizontalScrollIndicator={false}
onScroll={this._onScroll}>
{menuViews}
</ScrollView>
<PageControl
style={styles.pageControl}
numberOfPages={pageCount}
currentPage={currentPage}
currentPageIndicatorTintColor={color.primary}
pageIndicatorTintColor={color.gray}/>
<View style={styles.line}/>
<HomeGridView/>
<View style={styles.line}/>
</View>
);
}
_onScroll = (event) => {
const x = event.nativeEvent.contentOffset.x;
const page = Math.round(x / common.screen.width);
const {currentPage, setCurrentPage} = this.props;
if (currentPage !== page) {
setCurrentPage(page);
}
}
}
const styles = StyleSheet.create({
container: {
backgroundColor: 'white',
},
itemsView: {
flexDirection: 'row',
flexWrap: 'wrap',
width: common.screen.width
},
pageControl: {
margin: 10
},
line: {
backgroundColor: color.paper,
width: common.screen.width,
height: 10,
}
});
const mapStateToProps = (state) => ({menuInfos: state.homepageReudcer.homepage.menuInfo.items, currentPage: state.homepageReudcer.homepage.menuInfo.currentPage});
const mapDispatchToProps = (dispatch) => ({
setCurrentPage: (page) => {
dispatch(updateHomePageMenuPage(page));
}
})
export default connect(mapStateToProps, mapDispatchToProps)(HomeMenu)
複製代碼