react-native, react-navigation, redux 學習筆記

redux的使用

react-native, react, react-redux, react-navigaition, redux-thunk, redux-persistjava

用戶發出action, reducer函數算出新的state, view從新渲染react

三大原則

  1. 單一數據源,利用props的形式向下傳播(react數據流決定)redux

  2. state只讀,經過action修改react-native

  3. 經過純函數reducer來修改組件狀態,reducer是描述action動做的純函數緩存

react-redux 鏈接react和redux

import { connect, Provider } from 'react-redux'

connet([mapStateToProps], [mapDispatchToProps], [mergeProps])(App)

  • 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>

redux三劍客

// 先肯定一下初始狀態(狀態表示的格式)
export default {
    money: 0,
    lastJob:'no job'
}

ACTION

  • 定義動做,好比搶劫銀行、搬磚,可是怎麼搶怎麼搬仍是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'
    }
}

reducers

  • 描述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

store

  • 不一樣的組件能夠 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

more

中間件 middleware

  • 對store.dispatch的從新定義

  • 在發出action和執行reducer之間,添加了其餘功能

redux-thunk

使dispatch能夠接受函數說做爲參數,使異步的action能夠被觸發

// 不管killSomeOne是Action create仍是普通的返回{}的action
this.props.dispath(killSomeOne('vincent'))

redux-persist

本地保存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

react-navigation + redux

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);
相關文章
相關標籤/搜索