1.下載插件javascript
npm install redux --save npm install react-redux --save
2.項目結構java
3.redux
適用於 多交互,多數據源,複雜程度高的工程中。react
使用 redux 以前,基本的東西仍是要都懂的,數據流向介紹:android
Action:行爲。它的做用就是將咱們更新組件的 狀態(state) 的每一個動做抽象爲一個行爲,它有一個必須的參數 type,定義了 Action(行爲) 的名稱,其餘參數可自定義。寫法:npm
{ type: 'TEST_ACTION', // 定義Action的名稱 key1: 'value', ... keyN: value }
由於 Action 是個對象,因此,咱們須要建立這個對象,那建立這個對象的方法叫作 ActionCreator,寫法:redux
function testAction(key1: ?string, ..., keyN: ?string) { return { type: "TEST_ACTION", key1: key1, ... keyN: keyN } }
Reducer:reducer 的做用就是根據傳入的 Action行爲和舊的 state對象,返回一個新的 state ,而後組件會根據 state 刷新。當咱們肯定了組件的 state 對象結構 和 action 行爲的時候就能夠編寫 reducer 中的內容。寫法:react-native
function testReducer(state, action) { let key1 = action.key1; switch(action.type) { case TEST_ACTION: return { ...state, key1: key1 + '變化' }; default: return state; } }; export default testReducer;
固然咱們的工程中可能會有多個 reducer 的狀況,經過 combineReducers 能夠將多個 reducer 合成統一管理。app
import { combineReducers } from 'redux'; import testReducer1 from './testReducer1'; import testReducer2 from './testReducer2'; export default = combineReducers({ testReducer1, testReducer2 });
Store:當 reducer 返回了新的 state 後,這個 state 怎麼傳到組件和存儲就成了問題,redux 就是把這個狀態統一放到 store 中進行管理。ide
import { createStore } from 'redux'; const store = createStore(reducers);
上面的代碼根據 reducers 建立了一個 store方法集(它並非一個對象),而後再 store 中提供一些方法供咱們使用:函數
// 獲取當前 state store.getState() // 發送action,根據咱們前面 註冊的reducers 處理state store.dispath(action) // 替換當前 state 中的 reducer store.replaceReducer(nextReducer) // 添加監聽 store.subscribe(listener)
注:
另外 redux 有 5個 全局方法:
(1)createStore:建立一個redux store 來存儲應用中全部的state,應用中只能存在一個 store
createStore(reducer, [initialState],enhancer);
(2)combineReducers:把多個reducer函數做爲value的object,合併成一個reducers函數,而後就能夠經過reducers調用各個子reducer,state 對象的結構由傳入的多個 reducer 的 key 決定。
combineReducers(...reducers)
(3)...middlewares:每一個 middleware 接受 store 的 dispatch 和 getState 函數做爲命名參數,並返回一個函數。
1.該函數會被傳入被稱爲 next 的下一個 middleware 的 dispatch 方法,並返回一個接受 action 的新函數,這個函數能夠直接調用 next(action),或者在其餘須要的時刻調用,也可不調用。
2.調用鏈的最後一個 middleware 會接受真實的 store 的 dispatch 方法做爲 next 參數,並結束調用鏈。因此 middleware 的函數爲 ({ getState, dispatch }) => next => action。
3.返回值:一個應用了 middleware 後的 store enhancer。這個store enhancer 就是一個函數,而且須要應用到 createStore。它會返回一個應用了 middleware 的新 createStore。
(4)bindActionCreators:把 actionCreators 轉曾擁有同名 keys 的對象,讓 dispatch 把每一個 actionCreator 包裝起來,這樣就能夠直接調用它們。惟一使用 bindActionCreators 的場景是須要把 actionCreator 往下傳到一個組件上,卻不想讓這個組件察覺到 redux 的存在,並且不但願把 redux store 或者 dispatch 傳給它。
// actionCreators:一個 actionCreators 或 鍵值是 actionCreators 的對象 // dispatch:一個 dispatch 函數, 由 store 提供 bindActionCreators(actionCreators, dispatch)
返回值:一個與原對象相似的對象,只不過這個對象中的每一個函數值都直接 dispatch action。若是傳入的是個函數,返回的也是函數。
(5)compose(...fuctions):當須要多個 store 加強器 依次執行的時候使用它。compose 在應用常見的兩個用法:
// 1 let buildStore = compose( applymiddleware(thunk) )(createStore) // 2 let initStore = compose( applymiddleware(thunk) )
參數1(arguments):合成多個函數。每一個函數接受一個函數做爲參數,而後返回一個函數。
參數2(Function):從右往左把接受到的函數合成後的終極函數。
換張圖理解:
(1)首先,根據 redux官方文檔的示例 咱們能夠看出官方建議咱們將組件分紅 containers(容器組件)、components(模塊視圖組件)、redux 三大塊。因此咱們這邊文件的層級以下圖所示:
adb version adb devices
react-native init Test cd Test npm install --save redux npm install --save react-redux react-native start react-native run-android
ipconfig 8081端口
(2)接着,咱們再來完成視圖部分,而後根據視圖部分肯定哪些須要 redux 支持,再來生成相應的 action
與 reducer
文件。
1.首先,是 Main 文件,做爲咱們的容器組件放到 containers 文件夾內,Main 中的內容:
Main.js
/*主頁面*/ import React, { Component } from 'react'; import { StyleSheet, Text, View, TouchableOpacity, } from 'react-native'; // 引入 測試組件 import TestText from '../components/TestText' export default class Main extends Component { render() { return ( <View style={styles.container}> {/* 須要改變的組件 */} <TestText /> {/* 按鈕 */} <TouchableOpacity> <Text>改變文字按鈕</Text> </TouchableOpacity> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, });
那裏面咱們須要將 Text 做爲視圖組件獨立出來,因此將視圖組件 TestText 放到 components 文件夾中,TestText 中的內容:
TestText.js
/*測試組件*/ import React, { Component } from 'react'; import { Platform, StyleSheet, Text, View } from 'react-native'; export default class TestText extends Component { render() { return ( <Text>Welcome to React Native</Text> ); } }
(3)視圖部分咱們搭建完成,那麼咱們接着就是肯定須要哪些 action(行爲),那前面提到了,咱們是要點擊按鈕的時候讓文字發生改變,也就是說咱們當前須要一個改變文字的行爲,那咱們就將這個行爲命名爲 CHANGE_TEXT,那麼咱們須要初始化這個 action 這個對象,也就是前面咱們提到的 action creator:
action.js
/** * 步驟一 * 行爲 action */ // 定義行爲名稱 export const CHANGE_TEXT = 'CHANGE_TEXT'; // 初始化 CHANGE_TEXT 對象 export const changeText = (text) => { // 接收test參數 return { type: CHANGE_TEXT, // 名稱 text // 參數 默認值 } };
(4)action 文件配置完畢後,咱們就能夠根據需求來編寫 reducer 文件了,reducer 文件就是起到更新 state 的做用嘛,因此咱們將改變 文字 的邏輯放到這裏,當reducer 匹配到當前的點擊行爲爲 CHANGE_TEXT 時,就執行相應的操做,返回一個新的 state 給咱們使用,若是匹配不到,那麼就默認返回一個不變的新 state:
reducer.js
/** * 步驟二 * 操做 * 經過reducer操做action(根據action行爲建立reducer文件) */ /** * 引入 action * CHANGE_TEXT 類型(行爲名稱) * changeText 值 */ import { CHANGE_TEXT, changeText } from '../action/action'; /** * 建立 reducer * 根據名稱判斷是哪個行爲 * state = changeText('welcome to React Native') 初始化state */ const mainReducer = (state = changeText('welcome to React Native'), action) => { /** * state 不能直接改變 * 定義newState 接收state的值 */ const newState = state; const text = action.text; // 判斷 action 類型 switch (action.type) { case CHANGE_TEXT: return { // 返回全部的newState ...newState, text: '改變了' + text }; default: return { ...newState, text:state.text } } }; // 輸出口 export default mainReducer;
(5)配置完 action
和 reducer
兩個文件後,緊接着咱們就能夠根據 reducer
來初始化 store
了:
store.js
/** * 步驟三 * 初始化 store */ // 引入 reducer(操做) import Reducer from '../reducer/reducer'; // 獲取redux中的初始化方法 createStore import { createStore } from 'redux'; // 輸出 export default () => { // 根據 reducer 初始化 store const store = createStore(Reducer); return store; }
(6)redux
的東西已經都配置完成了,接着就剩下使用了,因此接下來要解決的問題就是怎麼發送行爲,怎麼接收 state(狀態)
,上面提到了,store
實際上是個方法集,咱們的 發送行爲 和 接收狀態
方法都在 store
中,因此只要拿到 store
,因此只要拿到 store
就能進行這兩個操做。
(7)那怎麼拿到 store
呢?在官方文檔中,清楚地告訴咱們,Provider
的任務就是將 store
傳給 connect
,而 connect
的做用是將咱們的組件進行第二次包裝,將操做數據的函數和數據的狀態包裝到 props
中,因此,首先,咱們須要對咱們的 Main
文件進行第一次包裝,咱們再新建一個 index
文件來對 Main
文件進行包裝:
Index.js
/** * 容器組件 * 入口文件 */ import React, { Component } from 'react'; // 引用外部文件 import { Provider } from 'react-redux'; import Main from './Main'; import configureStore from '../redux/store/store'; // 調用 store 文件中的 mainReducer常量中保存的方法 const store = configureStore(); // 定義根組件 export default class Root extends Component { render() { return( // 第一層包裝,爲了讓 main 可以拿到 store <Provider store={store}> <Main /> </Provider> ) } }
(8)包裝完成後,咱們的 Main 文件就能夠得到 store 了,那接着就是進行第二次包裝了,經過 connect 生成新組件:
Main.js
/*主頁面*/ import React, { Component } from 'react'; import { StyleSheet, Text, View, TouchableOpacity, } from 'react-native'; // 引入 測試組件 import TestText from '../components/TestText' /** * 獲取 react-redux的 connect() 方法 * 注:使組件層級中的 connect() 方法可以獲得 redux store */ import { connect } from 'react-redux'; // 獲取 action行爲的值 // import { CHANGE_TEXT } from '../redux/action/action'; import { changeText } from '../redux/action/action'; class Main extends Component { render() { // 經過 props 拿到保存的 onChangeText const { onChangeText } = this.props; return ( <View style={styles.container}> {/* 須要改變的組件 */} {/* 將父組件(Main)的props,傳遞給子組件(TestText)*/} <TestText {...this.props} /> {/* 按鈕 */} <TouchableOpacity // 設置按鈕點擊事件 onPress={onChangeText} > <Text>改變文字按鈕</Text> </TouchableOpacity> </View> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, }); /************ 初始化 ************/ // 獲取 state 變化 const mapStateToProps = (state) => { return { // 獲取 state 變化 value: state.text, } }; // 發送行爲 const mapDispatchToProps = (dispatch) => { return { // 發送行爲 // onChangeText: () => dispatch({type: CHANGE_TEXT}), onChangeText: () => dispatch(changeText('外部傳值')), } }; /** * 經過 connect() 方法 對Main組件進行第二層包裝 * 進行第二層包裝,生成的新組件擁有 接收和發送 數據的能力 * mapStateToProps 獲取狀態的函數 * mapDispatchToProps 發送行爲的函數 */ export default connect(mapStateToProps, mapDispatchToProps)(Main);
(9)到這裏,咱們的 新組件 就可以收發數據了,那怎麼接收和發送呢,別急,咱們接着就來完成 mapStateToProps(更新回調) 和 mapDispatchToProps(發送行爲) 兩個方法。首先,咱們須要經過 mapDispatchToProps 來發送行爲,而後經過 mapStateToProps 來監聽 state 的變化,這邊咱們須要發送的行爲 type 是 CHANGE_TEXT,當發送行爲以後,reducer 就會去匹配 行爲的類型,進行相應操做:
// 發送行爲 const mapDispatchToProps = (dispatch) => { return { onChangeText: () => dispatch(changeText('外部傳值')), } };
(10)當 reducer 接收到咱們觸發的 行爲 並進行一系列處理後,最終會返回一個新的 state,那麼 就會自動調用 mapStateToProps 來告訴系統,state 被操做了,那麼咱們就能夠經過 mapStateToProps 來獲取 state 狀態:
// 獲取 state 變化 const mapStateToProps = (state) => { return { value: state.text, } };
(11)那麼接下來咱們 怎麼改變文字 呢?前面提到,connect 做用就是生成一個新的組件,新的組件的 props 中包含了數據獲取和操做數據的函數,因此咱們須要讓 子組件拿到容器組件中的 props,而後在 子組件 中經過 props 就能夠拿到上面 定義的 value 和 onChangeText:
TestText.js
/*測試組件*/ import React, { Component } from 'react'; import { StyleSheet, Text, View } from 'react-native'; export default class TestText extends Component { render() { // 獲取 props 中的 value const { value } = this.props; return ( // 根據 value 改變內部文字 <Text>{value}</Text> ); } }
(12)效果圖
注:轉載 http://blog.csdn.net/yeshaojian/article/details/70599572
.