react-native-dva-starter: 集成 dva
前言
本教程是使用 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>
(未完待续...)
下面会为大家分享 本地存储的使用