react-native, react, react-redux, react-navigaition, redux-thunk, redux-persistjava
用戶發出action, reducer函數算出新的state, view從新渲染react
單一數據源,利用props的形式向下傳播(react數據流決定)redux
state只讀,經過action修改react-native
經過純函數reducer來修改組件狀態,reducer是描述action動做的純函數緩存
import { connect, Provider } from 'react-redux'
mapStateToProps: 基於全局的state,選擇咱們要注入的propsapp
不一樣的組件分開connec異步
function select(state){ return{ // 把state.todos注入,讀取方法: this.props.visibleTodo visibleTodo: state.todos } } const todoApp connect(select)(App) // export default todoApp
// store = "balabala" <Provider store={store}> <todoApp /> </Provider>
// 先肯定一下初始狀態(狀態表示的格式) export default { money: 0, lastJob:'no job' }
定義動做,好比搶劫銀行、搬磚,可是怎麼搶怎麼搬仍是reducer來定ide
/** * Created by liuyiman on 2017/7/3. */ // 定義一個menoy+的action function addmoney(money){ return { // 能夠用一個文件管理type,之因此是type是由於個人reducer要根據這個來判斷 type: 'ADD_MONEY', money } } function setLastJob(job){ return { type: 'SET_JOB', job } } // 定義一個賺錢的方式1 ,搶劫銀行 export function robBank(){ return (dispatch, getState) => { // 賺一百萬 let { earn } = getState() dispatch(addmoney(earn.money + 1000000)) return dispatch(setLastJob('robber')) } } // 定義一個賺錢的方式2,建材轉移者 export function moveBrick(){ return (dispatch, getState) => { console.log('s',getState()) let { earn } = getState() // 賺一塊錢 dispatch(addmoney( earn.money + 1 )) dispatch(setLastJob('brick mover')) } } // 破產,數據清零 export function goBroke() { return { type: 'BROKE', money: 0, job:'broke' } }
描述action如何改變store(in fact state)函數
import { combineReducers } from 'redux' import initializeState from './initializeState' // 定義一個reducer function earn( state = initializeState, action ) { switch (action.type) { case 'ADD_MONEY': return{ ...state, money:action.money } case 'SET_JOB': return{ ...state, lastJob:action.job } case 'BROKE': return{ ...state, money:action.money, lastJob:action.job } default: return state } } export default earn
不一樣的組件能夠 connet 到不一樣的 storeflex
import { createStore, applyMiddleware, compose, combineReducers } from 'redux' import thunkMidlleware from 'redux-thunk' import earn from './reducers' import { persistStore, autoRehydrate} from 'redux-persist' import { AsyncStorage } from 'react-native' // base reducer let baseReducers = { earn: earn } /* * 考慮到後面要將react-navigation的reducer加進來,使用redux-persist,因此寫了這個helper * const store = configStore(reducers)() * */ const configStore = function (reducers = {}) { const rootReducer = combineReducers({ ...baseReducers, ...reducers }) return function (_options = {}) { const store = createStore( rootReducer, _options.initialState, compose( applyMiddleware(thunkMidlleware), autoRehydrate() ) ) const options = { storage: AsyncStorage, blacklist: _options.blacklist } persistStore(store, options) return store } } export default configStore
對store.dispatch的從新定義
在發出action和執行reducer之間,添加了其餘功能
使dispatch能夠接受函數說做爲參數,使異步的action能夠被觸發
// 不管killSomeOne是Action create仍是普通的返回{}的action this.props.dispath(killSomeOne('vincent'))
本地保存store狀態(react-native 本地緩存),能夠設置白名單黑名單自動保存等等,特別好用
/* * 考慮到後面要將react-navigation的reducer加進來,使用redux-persist,因此寫了這個helper * const store = configStore(reducers)() * */ const configStore = function (reducers = {}) { const rootReducer = combineReducers({ ...baseReducers, ...reducers }) return function (_options = {}) { const store = createStore( rootReducer, _options.initialState, compose( applyMiddleware(thunkMidlleware), autoRehydrate() ) ) const options = { storage: AsyncStorage, blacklist: _options.blacklist } persistStore(store, options) return store } } export default configStore
import React, { Component } from 'react'; import { AppRegistry, StyleSheet, Text, View, Button } from 'react-native'; // navigation import { TabNavigator, addNavigationHelpers, StackNavigator } from 'react-navigation' // for connect redux and react import { Provider,connect } from 'react-redux' import configStore from './redux/store' // import actions import {moveBrick, robBank, goBroke} from './redux/actions' // initialState import initialState from './redux/store' // 賺錢頁面 class Earn extends Component { constructor(props) { super(props) } render(){ const { earn, dispatch } = this.props console.log( 'saa',initialState,earn ) return( <View style={styles.container}> <Text>先賺一個億!</Text> <Text>my money$:{earn.money}</Text> <Text>my last job:{earn.lastJob}</Text> <Button title="rob a bank" onPress={() => dispatch(robBank())}/> <Button title="move some Brick" onPress={() => dispatch(moveBrick())}/> <Text>價格指導:搬磚 -> $1; 打劫 -> $1000000</Text> <Button title="broke" onPress={() => dispatch(goBroke())}/> </View> ) } } // 傳入 earn頁面的redux const earnSelect = function (state) { return{ earn: state.earn } } // 鏈接,吧earn上面的select傳入earn的props裏面 const ConnnetedEarn = connect(earnSelect)(Earn) // tab navigation的另外一個頁面 class Screen extends Component{ constructor(props){ super(props) } render() { const { navigate } = this.props.navigation return( <View style={styles.container}> <Text>SCREEN!</Text> <Button title="to stack2" onPress={() => {navigate('Stack2')}}/> </View> ) } } // 註冊一個tag navigator const AppNav = TabNavigator({ 'earn':{ screen: ConnnetedEarn }, 'screen': { screen: Screen } }) // stack navigation 的頁面 class Stack2 extends Component { constructor(props){ super(props) } render(){ const {navigate} = this.props.navigation return ( <View style={styles.container}> <Text>Stack2</Text> <Button title="TO APP NAV" onPress={() => navigate('screen')}/> </View> ) } } /* * 註冊stack * 一個是 上面的 tag navigation的頁面 * 另外一個是 上面的 stack2 * */ const StackNav = StackNavigator({ App:{ screen: AppNav, title: 'app' }, Stack2: { screen: Stack2, title: 'stack2' } }) const navInitialState = StackNav.router.getStateForAction(AppNav.router.getActionForPathAndParams('screen')) const navReducer = (state = navInitialState, action) => { console.log('state:',state) let nextState = StackNav.router.getStateForAction(action, state); console.log('action', action) return nextState || state } /* * 加入navReducer,生成store * */ const store = configStore({ nav: navReducer })({ blacklist:['nav'] }) /* * stack app * 利用addNavigationHelper吧navigation傳進去 * */ class App extends Component{ render(){ return( <StackNav navigation={addNavigationHelpers({ dispatch: this.props.dispatch, state: this.props.nav })} /> ) } } /* * 把nav傳進去 * */ function select(state) { console.log('state',state) return { nav: state.nav } } /* * connect connect! * */ const ConnectedApp = connect(select)(App) // 加上 provider和store class reduxLearn extends Component { render() { return ( <Provider store={store}> <ConnectedApp/> </Provider> ); } } const styles = StyleSheet.create({ container: { flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor: '#F5FCFF', }, welcome: { fontSize: 20, textAlign: 'center', margin: 10, }, instructions: { textAlign: 'center', color: '#333333', marginBottom: 5, }, }); // 註冊 AppRegistry.registerComponent('reduxLearn', () => reduxLearn);