- 初始化项目,这里我使用的是 0.59.5 版本
react-native init myProject --version 0.59.5
2.安装 react-navigation 和 react-redux
yarn add react-navigation
react-redux
-
构建导航,最终呈现结果如下
image.png
下面的代码在项目的 App.js文件中编写
/**
* Sample React Native App
* https://github.com/facebook/react-native
*
* @format
* @flow
*/
import {
createBottomTabNavigator,
createAppContainer,
createStackNavigator,
createSwitchNavigator
} from 'react-navigation';
import Home from "./app/page/home";
import Setting from "./app/page/setting";
import Detail from "./app/page/detail";
import {AuthSwitch} from "./app/navigation/authNavigation";
import {createStore} from "redux";
import {counter} from "./app/redux/reducer";
import React, {Component} from 'react';
import {Provider} from "react-redux";
import {View} from 'react-native';
const tabNavigator = createBottomTabNavigator({
Home:{
//每个 tab 都是一个 stack,目的是可以单独控制 header
screen:createStackNavigator({
Home:{
screen:Home,
navigationOptions:{
header:null,
}
}
}),
navigationOptions:() => ({
tabBarLabel:'Home',
})
},
Setting:{
screen:createStackNavigator({
Setting:{
screen:Setting,
navigationOptions:{
header:null,
}
}
}),
navigationOptions:() => ({
tabBarLabel:'Setting',
})
},
}, {
initialRouteName:'Home',
swipeEnabled: false,
animationEnabled: false,
backBehavior:'none',
tabBarOptions: {
inactiveTintColor: '#808080',
activeTintColor: '#e9ab62',
labelStyle: {
fontSize: 12,
paddingTop: 3,
paddingBottom: 2
},
style: {
paddingTop: 4
}
}
});
const MainNavigator = createStackNavigator({
//tab 放在 stack 中,可以保证 navigate 到二级页面时隐藏底部 tabbar
Tab: {
screen: tabNavigator,
navigationOptions: {
header: null
}
},
Detail:{
screen: Detail,
navigationOptions: {
title: '详情',
}
}
}, {
headerMode: 'screen',
defaultNavigationOptions: {
headerBackTitle: null,
headerTitleStyle: {
color: 'white',
},
headerBackTitleStyle: {
color: 'white'
},
headerStyle: {
backgroundColor: '#37426A',
headerTransparent: true,
borderBottomWidth: 0,
borderBottomColor: 'transparent',
},
headerTintColor: 'white',
gesturesEnabled: true,
}
});
const RootStack = createStackNavigator({
Main:{
screen:MainNavigator,
},
AuthModal:{
screen:AuthSwitch,
}
}, {
mode: 'modal',
headerMode: 'none',
});
export const AppNavigator = createSwitchNavigator({
App: {
screen:RootStack,
},
});
const RootNavigator = createAppContainer(AppNavigator);
//创建 store
const store = createStore(counter);
export default class App extends Component {
render(){
return(
<Provider store={store}>
<View style={{ flex:1 }}>
<RootNavigator/>
</View>
</Provider>
)
}
}
- 导航中用到的 auth 模块
import {createStackNavigator, createSwitchNavigator} from "react-navigation";
import Login from "../page/login";
import Password from "../page/password";
export const BACKGROUND_STACK_CONFIG_PARENT = {
headerStyle:{ // 清除parent Header的底部线条
backgroundColor:'transparent',
borderBottomWidth:0,
shadowOpacity: 0, // android
elevation: 0 // android
},
headerTitleStyle:{
color:'white'
},
headerTransparent:true
};
//登录验证的 stack
const AuthNavigator = createStackNavigator({
Login:{
screen:Login,
navigationOptions:{
BACKGROUND_STACK_CONFIG_PARENT,
title:'Login',
}
},
Password:{
screen:Password,
navigationOptions:{
BACKGROUND_STACK_CONFIG_PARENT,
title:'Password',
}
}
});
//以AuthNavigator为基础构建 switch navigator
export const AuthSwitch = createSwitchNavigator({
AuthLogin:{
screen:AuthNavigator,
},
});
接下来,需要编写 action 和 reducer
- action 的编写
action就是一个 JavaScript 对象
//aciton.js
export const add = {
type:'ADD',
};
export const decrease = {
type:'DECREASE',
};
- reducer 的编写
reducer 是一个纯函数,输入一样的话,输出必定一样
//reducer.js
export function counter(state = {count:0}, action) {
let count = state.count;
switch (action.type) {
case 'ADD': {
return {
count: count + 1,
}
}
case 'DECREASE':{
return {
count: count - 1,
}
}
default:
return state;
}
}
- 在 home 页,用 connect 把组件包装为容器组件,从而能够获取全局的 state 和 dispatch 作为页面的 props
//home.js
import React, {PureComponent} from 'react';
import { Text, View } from 'react-native';
import {add, decrease} from "../redux/action";
import {connect} from "react-redux";
function mapStateToProps(state) {
return {
count:state.count
};
}
function mapDispatchToProps(dispatch) {
return{
addCount:() => dispatch(add),
decreaseCount:() => dispatch(decrease),
}
}
@connect(mapStateToProps, mapDispatchToProps)
class Home extends PureComponent {
constructor(props) {
super(props);
this.state = {
count:0
}
}
render() {
let {count, addCount, decreaseCount} = this.props;
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{fontSize:26}} onPress={() => this.props.navigation.navigate('Detail')}>Home!</Text>
<Text style={{fontSize:26, color:'red'}} onPress={() => addCount()}>ADD</Text>
<Text style={{fontSize:26, color:'red'}}>{count}</Text>
<Text style={{fontSize:26, color:'#459AFF'}} onPress={() => decreaseCount()}>DECREASE</Text>
</View>
);
}
}
export default Home;
至此,主要工作已经完成。
下面是剩下的几个页面
//detail.js
import React, {Component} from 'react';
import { Text, View } from 'react-native';
class Detail extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{fontSize:26}} onPress={() => this.props.navigation.navigate('Login')}>Detail!</Text>
</View>
);
}
}
export default Detail;
//login.js
import React, {Component} from 'react';
import { Text, View } from 'react-native';
class Login extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor:'#FFBE9E' }}>
<Text style={{fontSize:26}} onPress={() => this.props.navigation.navigate('Password')}>Login!</Text>
</View>
);
}
}
export default Login;
//password.js
import React, {Component} from 'react';
import { Text, View } from 'react-native';
class Password extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={{fontSize:26}} onPress={() => this.props.navigation.navigate('Home')}>Password!</Text>
</View>
);
}
}
export default Password;
//setting.js
import React, {Component} from 'react';
import { Text, View } from 'react-native';
class Setting extends Component {
render() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', backgroundColor:'#B7DEFF' }}>
<Text style={{fontSize:26}}>Setting</Text>
<Text style={{fontSize:26}}>Setting!</Text>
</View>
);
}
}
export default Setting;
最后需要注意的是,为了支持装饰器语法,需要额外安装几个三方库
yarn add babel-plugin-transform-decorators-regacy
yarn add @babel/plugin-transform-runtime
yarn add react-native-typescript-transformer
安装完成后,在项目中新建一个 .babelrc配置文件,然后输入以下内容
{
"presets": ["module:metro-react-native-babel-preset"],
"plugins":[
["@babel/plugin-proposal-decorators", { "legacy": true }]
]
}
P.S.如果安装的是 react-redux 7.0以上版本,那么下面的语句会导致在 debug 模式下不能运行,目前还没找到解决办法,我暂时在 release 下运行的。
具体可参考:https://github.com/facebook/react-native/issues/24458
@connect(mapStateToProps, mapDispatchToProps)
参考文档:
https://reactnavigation.org/en/
http://cn.redux.js.org
demo 地址:
https://github.com/mike1023/react-native-react-redux
网友评论