react-native-dva-starter: 集成 dva 和 react-navigation 典型应用场景的 React Native 实例

前言

本教程是使用 create-react-native-app 创建基于 dva,react-native,antd 的 react-navigation 综合案例

相关的 react-navigation的配置请参考 https://www.jianshu.com/nb/21581559
下面用到了 修饰器 @connect() 请参考 阮大爷的教程 http://es6.ruanyifeng.com/
如果对 dva 不是很了解 请参考 https://www.jianshu.com/nb/20964535
或者 官方文档https://github.com/Sawyer-china/dva
本文案例地址:https://github.com/Sawyer-china/react-navigation-dva-antd
现在我们就开始一步一步的构建 如遇见问题可 添加 qq群:218618405 进行提问

如果你觉得该文章对你有帮助加个喜欢,github 加个 start 谢谢

1. 创建项目 react-native-dva-antd

create-react-native-app 的安装方式我就不在阐述,如果有问题欢迎 + QQ群进行咨询

$ create-react-native-app react-native-dva-antd

进入工程目录

$ cd react-native-dva-antd 

运行

$ yarn start  
// 如果遇到管理员权限问题:
// error: EACCES: permission denied, open '/Users/ectouch/.expo/log'  
// 使用 sudo yarn start

使用 expo 扫码查看项目运行效果

2. 引入我们需要的基础包

$ yarn add dva react-navigation@1.0.0beta.27 antd-mobile react-redux react-native-vector-icons react-dom --save

注:react-navigation 版本请以 react-navigation@1.0.0beta.27为准,版本高了会有意外的情况发生

3. 创建 Home 页面

在根目录下面创建 containers 的文件夹然后 创建 Home.js 文件 并写入以下代码

import React, { Component } from 'react'
import { StyleSheet, View, Text } from 'react-native'
import { connect } from 'react-redux'
import { Button } from 'antd-mobile'
import Ionicons from 'react-native-vector-icons/Ionicons'

// @connect()  es7 的语法 修饰器 如果对这个不是很了解请看 阮大爷的 教程  http://es6.ruanyifeng.com/
@connect()
class Home extends Component {
    static navigationOptions = {
        title: 'Home',
        tabBarLabel: '首页',
        tabBarIcon: ({ tintColor, focused }) =>
            // focused 当前 tab 被选择  !focused  未被选中
            // tintColor tabNavigator 传入的配置颜色
            <Ionicons
                name={focused ? 'ios-home' : 'ios-home-outline'}
                size={26}
                style={{ color: tintColor }}
            />
    }

    render() {
        return (
            <View style={styles.container}>
                <Text style={{ marginBottom: 20 }}>这是首页</Text>
                <Button type="warning">default</Button>
            </View>
        )
    }
}

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center'
    },
    icon: {
        width: 32,
        height: 32
    }
})

export default Home

创建 Cart.js, Category.js, Search.js, User.js 页面 请查看
github: https://github.com/Sawyer-china/react-navigation-dva-antd

4. 在根目录创建 router.js

import React, { PureComponent } from 'react'
import {
    BackHandler,
    Animated,
    Easing,
    View,
    Text,
    StyleSheet,
    ActivityIndicator
} from 'react-native'

import {
    StackNavigator,
    TabNavigator,
    TabBarBottom,
    addNavigationHelpers
} from 'react-navigation'

import { NavigationActions } from '../utils'

import { connect } from 'react-redux'

import Home from './containers/Home'
import Cart from './containers/Cart'
import User from './containers/User'
import Category from './containers/Category'
import Search from './containers/Search'

const Loading = () =>
    <View style={styles.container}>
        <ActivityIndicator />
    </View>

const styles = StyleSheet.create({
    container: {
        flex: 1,
        alignItems: 'center',
        justifyContent: 'center'
    }
})

const HomeNavigator = TabNavigator(
    {
        Home: { screen: Home },
        Category: { screen: Category },
        Cart: { screen: Cart },
        User: { screen: User }
    },
    {
        tabBarComponent: TabBarBottom,
        tabBarPosition: 'bottom',
        swipeEnabled: false,
        animationEnabled: false,
        lazyLoad: true,
        tabBarOptions: {
            activeTintColor: '#ff0000'
        }
    }
)

const AppNavigation = StackNavigator(
    {
        Home: {
            screen: HomeNavigator
        },
        Search: { screen: Search }
    },
    {
        headerMode: 'screen'
    }
)
@connect(({ router }) => ({ router }))
class Router extends PureComponent {
    render() {
        const { dispatch, app, router } = this.props
        const navigation = addNavigationHelpers({ dispatch, state: router })
        return <AppNavigation navigation={navigation} />
    }
}

export function routerReducer(state, action = {}) {
    return AppNavigation.router.getStateForAction(action, state)
}

export default Router

并创建 models/router.js 的 model 和 utils/dva.js 请参考github 地址
router文件是 router 的相关信息
dva 是启用这个项目的文件

5. 修改 根目录 App.js 文件

import React, { Component } from 'react'

import dva from './utils/dva'
import Router from './router'

// import appModel from './models/app'
import routerModel from './models/router'

const app = dva({
    initialState: {},
    models: [routerModel],
    onError(e) {
        console.log('onError', e)
    }
})

const App = app.start(<Router />)

export default App

6. 如何进行页面跳转

打开Home.js页面

<Button
    type="warning"
    onClick={() => {
       this.props.dispatch(
            NavigationActions.navigate({ routeName: 'Search' })
       )
    }}
>
    点我到搜索页面
</Button>

6. Ionicons 的使用方式

Ionicons 是一个字体库 使用方法如下所示:
实际打包时你需要集成该字体包才可能正确的打包 应用 ,
具体用法可百度 react-native-vector-icons

......
import Ionicons from 'react-native-vector-icons/Ionicons' 
// 因为我们在创建项目的时候已经安装了该包了,所以可以直接引入
......
class Home extends Component {
    static navigationOptions = {
        header: null,
        tabBarLabel: '首页',
        tabBarIcon: ({ tintColor, focused }) =>
            // focused 当前 tab 被选择  !focused  未被选中
            // tintColor tabNavigator 传入的配置颜色
            <Ionicons
                name={focused ? 'ios-home' : 'ios-home-outline'}
                size={26}
                style={{ color: tintColor }}
            />
    }
......
}

7. 在案例中实现登录退出的基本原理

(登录页面我们会用到本地存储的功能)
安装有reactnative 中文网提供的本地存储插件

$ npm install react-native-storage --save

创建 app models (在models目录下创建 app.js)

export default {
    namespace: 'app',
    state: {
        isLogin: false // 登录状态
    },
    reducers: {
        
    },
    effects: {
    }
}

修改User.js页面 render 函数中的 return

如果页面登录了,就显示退出登录按钮,否则显示 我要登录

return (
            <View style={styles.container}>
                <Text style={{ marginBottom: 20 }}>会员中心</Text>
                {!isLogin
                    ? <Button
                          type="warning"
                          onClick={() => {
                              this.props.dispatch(
                                  NavigationActions.navigate({
                                      routeName: 'Login'
                                  })
                              )
                          }}
                      >
                          我要登录
                      </Button>
                    : <View>
                          <Text style={{ marginBottom: 20 }}>您已经登录了</Text>
                          <Button
                          type="warning"
                          onClick={() => {
                              console.log('退出成功')
                          }}
                      >
                        退出登录
                      </Button>
                      </View>}
            </View>
        )

在 Login.js 页面中添加 onLogin 方法 调用 models/app.js 中的login 改变状态

...
onLogin = () => {
    this.props.dispatch({ type: 'app/login' })
}
...
<Button type="ghost" onClick={this.onLogin}>
    确认登录
</Button>
修改 models/app.js

增加 state状态

state:{
    isLogin: false,
    fetching: false // 加载进度条
}

增加 login 方法

*login({ payload }, { call, put }) {
            yield put({ type: 'updateState', payload: { fetching: true } })
            const login = yield call(authService.login, payload)
            if (login) {
                yield put({
                    type: 'updateState',
                    payload: { isLogin: true, fetching: false }
                })
                yield put(NavigationActions.back())
            }
        }

修改 containers/Login.js 页面增加活动指示器

import { Button, ActivityIndicator } from 'antd-mobile'

...
render() {
        const { fetching } = this.props
        return (
            <View style={styles.container}>
                <ActivityIndicator
                    text="正在加载"
                    toast={true}
                    color="#ff0000"
                    animating={fetching}
                />
                <Text style={{ marginBottom: 20 }}>我是登录页面</Text>
                <Button type="ghost" onClick={this.onLogin}>
                    确认登录
                </Button>
            </View>
        )
    }
增加退出功能

修改 models/app.js 增加logout方法

*logout({ payload }, { call, put }) {
    yield put({ type: 'updateState', payload: { isLogin: false } })
}
修改 containers/User.js

增加 logout 方法

logout = () => {
    this.props.dispatch({ type: 'app/logout' })
}

修改 退出登录 按钮的事件

<Button type="warning" onClick={this.logout}>
    退出登录
</Button>

(未完待续...)
下面会为大家分享 本地存储的使用

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350