从0到1打造一款react-native App(二)Navigation+Redux

时间:2022-06-24
本文章向大家介绍从0到1打造一款react-native App(二)Navigation+Redux,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/j_bleach/article/details/80714844

前言

很久没写东西了,发现时间过的真快。之前想学习下RN,但是由于自己的懒惰挖了个坑,最近正好公司开了RN的项目,我也把很久以前挖的坑填一下!新开的这个项目只有我一个人搞,之前没做过RN,这次正好可以边做边学,还是很开心的,享受这种探索的过程。开始!

App

环境搭建好之后,就开始开发了。还是先大致介绍下这个小项目,这次主要大致会完成以下几个功能:

  1. 摄像头相关(二维码扫描,拍照摄像等等,类似微信拍照,但是拍出的照片要求不能在系统相册显示,因此会涉及到文件操作相关)。
  2. 地理信息(签到功能,后续可能会对接一款地图吧)。
  3. NFC(身份证,门禁卡读取)。
  4. 基础的展示页(长列表等等吧)。 这是目前的项目结构:

和之前搭的PC差不多,项目结构都千篇一律,多了一个navigation的文件夹。接下来就介绍这个。

最初在搭建RN的项目,主要是参照react-native的文档,所以很多时候还是不大清楚到底该用什么,比如路由。Navigation是网上提及比较多的应用包,因此本项目也使用了这个。

本项目用的navigation版本是v2.2.5,大家在用的时候一定要看清楚版本,不同版本的api还是有差异的,然后去看英文的文档,这里我还被坑了一下。

navigation的路由入口是由一个StackNavigator创建的,也就如名字一样是一个堆栈式的路由数据,在2.2.5版本已经由StackNavigator变为createStackNavigator了。目前app只做了一个主页面和一个二维码扫描的跳转页。即:

const AppNavigator = createStackNavigator(
        {
            Home: {
                screen: MainScreenNavigator,
                navigationOptions: {
                    title: '首页'
                }
            },
            QRcode: {
                screen: QRcode,
                navigationOptions: {
                    header: null
                }
            }
        }
);

主要的页面都写在了MainScreenNavigator。

MainScreenNavigator用了通常app采用的底部tab的呈现方法,界面预览:

在navigation中主要有两种导航的表现形式,一种是Tab navigation,另一种是Drawer navigation,这里采用的tab的表现方式,而drawer 类似于侧边抽出的,目前还没有用到。目前下方的tab主要分为5个,即:

const MainScreenNavigator = createMaterialBottomTabNavigator(
        {
            Home: {
                screen: Home,
                navigationOptions: {
                    title: '首页',
                    tabBarIcon: tabBarIcon('home')
                }
            },
            Photo: {
                screen: Photo,
                navigationOptions: {
                    title: '拍照',
                    tabBarIcon: tabBarIcon('photo-album')
                }
            },
            NFC: {
                screen: Setting,
                navigationOptions: {
                    title: 'NFC',
                    tabBarIcon: tabBarIcon('credit-card')
                }
            },
            Upload: {
                screen: Upload,
                navigationOptions: {
                    title: '上传',
                    tabBarIcon: tabBarIcon('cloud-upload'),
                }
            },
            Setting: {
                screen: Setting,
                navigationOptions: {
                    title: '设置',
                    tabBarIcon: tabBarIcon('settings')
                }
            }
        },
        {
            shifting: true,
            backBehavior: 'none', 
            initialRouteName: 'Home',
            activeTintColor: '#ffffff',
            inactiveTintColor: '#eeeeee',
            barStyle: {
                backgroundColor: '#4177F6',
                paddingBottom: 20,
                height: 50
            }
        }
);

这个tab用到了他官方推荐的一个react-navigation-material-bottom-tabs插件,在使用这个插件时需要去引入icons,我这里引入的是这个。

顺便说一下,react-native推荐的包管理工具是yarn,最好使用yarn可以省很多事,因为我这边(ubuntu16.04)如果用npm安装的话,就不能正常使用react link xx的功能,link是帮我们自动去关联一些依赖以及gradle的。

navigation的一些配置可以在creat的时候去写,比如声明一个tab的名称为上传。

        Upload: {
                screen: Upload,
                navigationOptions: {
                    title: '上传',
                    tabBarIcon: tabBarIcon('cloud-upload'),
                }
            },

也可以在具体的业务组件里面去定义静态方法,如:

class Upload extends PureComponent {
    static navigationOptions = {
        tabBarOnPress: async ({ defaultHandler, navigation }) => {
            const { navigate } = navigation;
            const files = await storageFile();
            navigate('Upload', { files });
        }
    };
   }

比如在点击Upload的tab时,去触发一个存储文件的方法(storageFile是自定义的方法)。

这里我个人觉得一些静态的title,或者样式上的配置,就直接在总的MainScreenNavigator中写好就行了,而涉及到一些具体的业务需求,方法,就在具体的组件模块里去写,比较方便管理和维护。

navigation大体介绍到这里,之后有在项目中新增的东西,会继续同步过来。

Redux

最初在项目搭建的时候,还是像将redux引入react 的方式,去引入到react-native的。即用react-redux提供的Provider在根页面将app包裹起来,然后去把reducer注入到store当中去。但是有些情况下,可能需要navigation的配合,因此需要去整合navigation进来。

在navigation v2.2.5中将很多api独立了出来,单独分了一个react-navigation-redux-helpers的模型。大体思路还是没有变,根页面引入react-redux。

import React, {
    Component
} from 'react';
import { Provider } from 'react-redux';
import store from './redux/store';
import Navigation from './navigation';
import { YellowBox } from 'react-native';

YellowBox.ignoreWarnings(['Warning: isMounted(...) is deprecated', 'Module RCTImageLoader']);


class App extends Component {
    render() {
        return (
                <Provider store={store}>
                    <Navigation />
                </Provider >
        );
    }
}

export default App;

在store当中增加对navigation的整合:

import { createStore, combineReducers, applyMiddleware } from 'redux';
import * as reducer from '../reducer/';
import thunk from 'redux-thunk';
import AppNavigator from '../../navigation/route';
import { createNavigationReducer, createReactNavigationReduxMiddleware } from "react-navigation-redux-helpers"; // 中间件,有了这个就可以支持异步action

const navReducer = createNavigationReducer(AppNavigator);
const middleware = createReactNavigationReduxMiddleware(
        "root",
        state => state.nav
);

const store = createStore(
        combineReducers({ ...reducer, nav: navReducer }),
        applyMiddleware(middleware)
);

export default store;

navigation组件去做一些初始属性的配置:

import React, {
    Component
} from 'react';
import { connect } from 'react-redux';
import {
    createNavigationPropConstructor,       // handles #1 above
    initializeListeners,                   // handles #4 above
} from 'react-navigation-redux-helpers';
import AppNavigator from './route.js';


const navigationPropConstructor = createNavigationPropConstructor("root");

class Navigation extends Component {
    componentDidMount() {
        initializeListeners("root", this.props.nav);
    }

    render() {
        this._navigation = navigationPropConstructor(
                this.props.dispatch,
                this.props.nav,
                AppNavigator.router,
                () => this._navigation
        );
        return (
                <AppNavigator navigation={this._navigation} />
        );
    }
}
const mapStateToProps = (state) => ({
    nav: state.nav,
});


export default connect(mapStateToProps)(Navigation);

关于navigation+redux我这里就没有去细讲了,因为自己也是完全去照搬官方文档,如果有同学去做到这一块的话,以官方文档为参考就ok。

在做navigation这一块,个人感觉还是比较简单好理解的,唯一不好的地方是版本之间差异较大,最初v2.2.5开发完之后,去重新下载项目依赖,navigation往上升了2个小版本,结果就不行了,而这中间也就隔了3,4天而已,所以配置相关的东西还是要去看最新的文档。

目前这个项目自己做了一个星期左右,大体功能除了地图sdk的对接外,基本功能都完成了,不过必然还有很多地方做的不正确。所以欢迎同样正在学习的同学一起交流讨论,也欢迎熟手来指导。

项目地址:https://github.com/jiwenjiang/react-native-nfc