美文网首页Web前端之路
react-native的学习

react-native的学习

作者: Dottie22 | 来源:发表于2017-06-22 23:41 被阅读1536次

    最近突然对react-native感兴趣. 主要被它在iOS和安卓平台通用性吸引, 就花了几天的课余时间学习了一下. 也稍微有点小收获, 想跟大家分享一下. 这门技术在2015年也是火的可以, facebook推出的, 声称是 learn once, write anywhere(感觉就跟java一样, 一次书写,到处运行).hhhh, 我也比较捣鼓新技术, 加上之前开发过iOS, 有点移动端开发基础,后台也熟悉, 所以感觉学起来还算是轻松.

    . 具体的环境配置就就不跟大家讲, 网上的教程还挺多, 也很详细.

    如.
    react-native init DemoRN
    npm install --save react-navigation
    react-native run-ios
    等等.
    

    . 跟大家分享是以下一些知识点:(涉及到内容不多, 后续继续补充哈)

    1. es6中export和import的介绍.
    2. 以及一些基础的(props, state的区别)
    3. es6中fetch进行网络请求的简单介绍.
    4. react-navigation, 这里主要介绍StackNavigator和TabNavigator,类似iOS中UINavigationController和TabBarController.
    5. 正向传值和逆向回调传值
    6. ListView的使用(类似iOS中UITableView,不过还是有点区别)
    7. 如何书写一些公共模块(将一些常用的功能抽取到一个Util类中)
    8. 以及一些全局的常量如何归类.
    9. 关于style样式.
    10. 生命周期函数

    按照惯例啦----先看效果图.
    (本来已经录好了gif给大家看的, 发现上传到简书失败,估计后台有文件大小限制, 也尝试了压缩gif, 可是文件还是有点大, 就只能截图给大家看了,不开心啊), 大家将就点吧.

    Simulator Screen Shot 2017年6月22日 23.36.57.png Simulator Screen Shot 2017年6月22日 23.37.03.png Simulator Screen Shot 2017年6月22日 23.37.09.png Simulator Screen Shot 2017年6月22日 23.37.11.png Simulator Screen Shot 2017年6月22日 23.37.21.png Simulator Screen Shot 2017年6月22日 23.37.24.png

    1. es6中的import和export的简单介绍.

    Home.js文件
    这里是导出默认的模块. Home,
    注意一个js文件中只能有一个默认的导出的模块. 
    export default class Home extends Component {
        
    }
    
    index.ios.js文件
    注意, 这样在使用import的时候,是可以自定义导入的默认模块的名字的 
    import Home from './Home';
    
    
    可能你在一些文件中会看到这样的导入方式:
    import React, {Component} from 'react';
    这里我解释下哈
    React模块是react.js文件默认导出的文件.
    {Component}注意这里加了大括号, 表示react.js文件中非默认导出
    (即没有default关键修饰导出的模块), 还有注意一点的是
        非默认模块在import的时候是不可以重命名的.
    

    2. 关于props和state的简单介绍.

    RN的组件其实就是一个状态机, 主要的两个参数就是props和state, 
    最后返回一个虚拟DOM, 进行渲染.(这也是它的高效原因之一).
    
    props 一般用于父组件向子组件通信,在组件之间进行传值使用.
    state 一般用于组件内部的状态维护, 跟新组件内部数据, 状态, 重新进行虚拟DOM的渲染.
    注意:
    1. 不管是props还是state的改变, 都会引发render函数的重新调用.
    2. 都可以由组件自身提供的函数进行初始化.
    3. props是一个父组件传递给子组件的数据流 getDefaultProps
    4. state只能在自身组件中setState   getInitalState
    5. getDefaultProps和getInitalState在es6中推荐用constructor进行初始化.
    
    如:
      constructor(props) {
        super(props);
        let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = {
            isLoaded: false,
            dataSource: ds
        }
    }
    

    3.fetch进行网络请求的简单介绍.

    一个最简单的请求就是这样:
     fetch(url).then((response) => {
            return response.json();
        }).then((responseData) => {
            callBack(responseData[objectName]);
        }).catch((error) => {
            alert(error);
        })
    

    当然这里你也可以指定请求方式, 请求头, 以及请求参数, (由于示例,未详细介绍, 具体还请读者自行去查哈).

    4 StackNavigator的使用.

    注意要导入 
    import {StackNavigator, TabNavigator} from 'react-navigation';
    

    StackNavigator是facebook最近才推出的react-navigation框架中所带的一个模块, 超级好用, 比之前的那些navigatorIOS好用多了. gitHub上的star也猛增.

    示例:
    const Nav2 = StackNavigator(
    {
        personCenter: {screen: PersonCenter},
        movieList:{screen:MovieList},
    },
    {
        navigationOptions:{
            headerStyle:{
                backgroundColor:"#eec",
            }
        }
    }
    );
    
    import PersonCenter from './MyApp/PersonCenterModule/PersonCenter';
    import MovieList from './MyApp/PersonCenterModule/MovieList';
    这里PersonCenter和MovieList是导入的另外两个模块, 前面的名称是可以自定义的.
    navigationOptions的就是全局的导航栏的设置.(会影响每一个导航栏). 当然也可以在
    每个页面进行单页面自定义.
    如:
    export default class MovieList extends Component {
    
    static navigationOptions = {
        tabBarVisible: false,
        title: "科技新闻"
    }
    }
    

    讲导航栏肯定少不了页面跳转.
    导航栏提供了一些函数和属性.这里介绍常用的.

    this.props.navigation.navigate('需要跳转到的页面', {参数传递, 回调函数的定义})
    this.props.navigation.goBack()返回上一级
    this.props.navigation.state.params 获取传递参数的值.
    或许读者会对这样的写法有疑问:
    const {params} = this.props.navigation.state.params, 我解释下哈
    这样是相当于等价先判断this.props.navigation.state中是否有params这个属性,
    如何没有程序运行时会由警告.
    
    如:
    跳转至homeSecond页面,并且将传递titleValue值. 这里homeSecond是在导航控制器
        {screen: PersonCenter}
    这里指定的.
    <Button title="详情" onPress={() => {
                const {navigate} = navigation;
                navigate('homeSecond', {titleValue: "哈哈"})
            }}/>
    

    5 正向传值和逆向回调传值

    先看代码咯:
    export default class HomeSecond extends Component {
    static navigationOptions = {
    title: "HomeSecond",
    tabBarVisible:false
    }

    constructor(props) {
        super(props);
        const {params} = props.navigation.state;
        this.state = {
            titleValue: params.titleValue
        }
    }
    
    render() {
        const {navigate} = this.props.navigation;
        return (
            <View style={styles.container}>
                <Text style={styles.text}>{this.state.titleValue}</Text>
                <Button title="继续点击"
                        onPress={() => navigate('homeThird',
                            {
                                titleValue: this.state.titleValue,
                                username: "React-Native",
                                callBack: (data) => {
                                    this.setState({
                                        titleValue: data
                                    });
                                }
                            })
                        }/>
            </View>
        );
    }
    }
    

    这里首先初始化state, 有一个属性为titleValue, 这里是作为接收下级界面回调传回的值.

    navigate('homeThird',{
        titleValue: this.state.titleValue,
        username: "React-Native",
        callBack: (data) => {
            this.setState({
                titleValue: data
            });
    }
    
    由于该界面是在导航控制器(StackNavigator)的管理下, 
    所以该界面的this.props会   自动有一个navigatioin参数, 
    那么就可以使用这个navigation中的navigate进行界    面跳转和参数传递了啊.
    const {navigate}  = this.props.navigation;
    利用该参数先进行跳转到homeThird.js页面. 并且传递titleValue和username的值, 
    以及一个callback的回调函数.
    
    
    
    下面看homeThird.js页面如何接收的.
      
      这里接收titleValue和username.
      constructor(props) {
        super(props);
        this.state = {
            textInputValue: props.navigation.state.params.titleValue,
            username:props.navigation.state.params.username
        }
    }
    
    render() {
        const {params} = this.props.navigation.state;
        return (
            <View style={styles.container}>
                <Text style={styles.text}>{params.username}</Text>
                <TextInput style={styles.textInputViewStyle}
                           placeholder="请输入"
                           onChangeText={(text) => this.setState({textInputValue: text})}/>
                <Button title="确认并返回"
                        onPress={this.clickBackBtn.bind(this)}/>
            </View>
        );
    }
    
     clickBackBtn() {
        const {goBack} = this.props.navigation;
        const {params} = this.props.navigation.state;
        params.callBack(this.state.textInputValue);
        goBack();
    }
    
    这里先获取到前一个界面传递过来的参数params, 
    得到回调函数callBack进行回调传值. 将输入框中的值逆传给上一个界面.
    

    6. TabNavigator的简单使用

    注意要导入 
    import {StackNavigator, TabNavigator} from 'react-navigation';
    

    和StackNavigator非常相似.

    const HelloRN = TabNavigator(
    {
        first: {
            screen: Nav1,
            navigationOptions: {
                tabBarLabel: '主页',
                tabBarIcon: ({tintColor}) => (
                    <Image style={{tintColor: tintColor}} source={require('./MyApp/images/tab_groups@2x.png')}/>)
            },
        },
        second: {
            screen: Nav2,
            navigationOptions: {
                tabBarLabel: "我的",
                tabBarIcon: ({tintColor}) => (
                    <Image style={{tintColor: tintColor}} source={require('./MyApp/images/tab_settings@2x.png')}/>)
            }
        },
    },
    
    //这里设tabbar的一些全局属性, 会影响所有的页面中的tabbar.
    {
        animationEnabled: false, // 切换页面时是否有动画效果
        tabBarPosition: 'bottom', // 显示在底端,android 默认是显示在页面顶端的
        swipeEnabled: false, // 是否可以左右滑动切换tab
        backBehavior: 'none', // 按 back 键是否跳转到第一个Tab(首页), none 为不跳转
        tabBarOptions: {
            activeTintColor: '#17e', // 文字和图片选中颜色
            inactiveTintColor: '#666', // 文字和图片未选中颜色
            showIcon: true, // android 默认不显示 icon, 需要设置为 true 才会显示
            indicatorStyle: {
                height: 0  // 如TabBar下面显示有一条线,可以设高度为0后隐藏
            },
            style: {
                backgroundColor: '#eee', // TabBar 背景色
                height: 44, //默认为44
            },
            labelStyle: {
                fontSize: 14, // 文字大小
            },
        },
    }
    );
    

    7 ListView的使用

    //创建一个DataSource数据源.
    constructor(props) {
        super(props);
        //这里进行DataSource的创建, 指定渲染策略.
        let ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
        this.state = {
            isLoaded: false,
            dataSource: ds
        }
    }
    
    //进行数据请求. 获取数据,更新state 进而重新渲染页面,
    //注意只要state中的值发生变化就会进行render方法的调用.
    componentDidMount() {
        Util.getRquest(Constants.IMOOC_API, (data) => {
            this.setState({
                dataSource: this.state.dataSource.cloneWithRows(data),
                isLoaded: true
            });
        }, "data");
    }
    
    页面渲染
    render() {
        if (!this.state.isLoaded) {
            return this.renderLoadingView();
        }
        return (
            <View style={styles.container}>
                <ListView
                    style={styles.listView}
                    dataSource={this.state.dataSource}
                    renderRow={this._renderRow.bind(this)}
                    initialListSize={10}/>
            </View>
        );
    }
    
    渲染每一行
    _renderRow(model) {
        return (
            <View style={styles.rowContainer}>
                <Image source={{uri: model.picSmall}} style={styles.cellImage}/>
                <View style={styles.textContainer}>
                    <Text style={styles.title}>{model.name}</Text>
                    <Text style={styles.subTitle}>{model.description}</Text>
                </View>
            </View>
        )
    }
    
    //加载等待的view
    renderLoadingView() {
        return (
            <View style={{flex: 1, alignItems: "center", justifyContent: "center"}}>
                <Text style={{fontSize: 18, color: "#17e"}}>
                    加载中...
                </Text>
            </View>
        );
    }
    

    8 公共模块和全局常量的书写.

    Constants.js文件

    /**
    *定义APP需要要的全局常量文件.
    * 存放全局的const, 如:公共的API, 以及主题等.
    */
    
    const Constatnts = {
        /**
         * 新闻接口API
         */
        NEWS_API : 'http://c.m.163.com/nc/article/list/T1348649580692/0-20.html',
        /**
         * 慕课网API
         */
        IMOOC_API:"http://www.imooc.com/api/teacher?type=4&num=30"
    };
    
    export default Constatnts;
    

    MyUtils文件如下. 常用的工具如设备屏幕的宽高, 设备的操作系统.以及get请求方法的封装.

    const Dimensions = require('Dimensions');
    const Platform = require('Platform');
    
    export default class MyUtils {
    
    static getScreenWidth() {
        return Dimensions.get('window').width;
    }
    
    static getScreenHeight() {
        return Dimensions.get('window').height;
    }
    
    static getPlatformOS() {
        return Platform.OS;
    }
    
    static getRquest(url, callBack, objectName) {
        fetch(url).then((response) => {
            return response.json();
        }).then((responseData) => {
            callBack(responseData[objectName]);
        }).catch((error) => {
            alert(error);
        })
    }
    }
    

    9 关于style样式的简单介绍

    你可以内联这样写, 注意这里要加两个大括号, 外层大括号是javascript的语法. 内层大括号是jsx的语法.

     <View style={{flex:1,alignItems:"center", justifyContent:"center"}}>
        <Text style={{ fontSize:18, color:"#17e"}}>
            加载中...
        </Text>
     </View>
    

    当然, 更推荐这样的方式(外联).

    const styles = StyleSheet.create({
    ListView: {
        marginTop: 20,
        backgroundColor: "#F5FCFF"
    },
    rowContainer: {
        flexDirection: "row",
        flex: 1,
        paddingTop: 5,
        paddingBottom: 5,
        borderBottomWidth: 1,
        borderColor: "#666"
    },
    image: {
        width: 120,
        height: 100,
        marginLeft: 10
    },
    textContainer: {
        flex: 1,
        paddingLeft: 10,
        paddingRight: 10,
        justifyContent: "space-around"
    },
    title: {
        color: "black",
        fontSize: 15
    },
    subtitle: {
        color: "#666",
        fontSize: 13,
        textAlign: "right",
    }
    });
    
    /**
     * justifyContent是垂直方式
     * alignItems是水平方式
     *
     * 具体的样式有:
     * 1. center 容器内居中对齐
     * 2. flex-start 从容器的头部开始排列
     * 3. flex-end 从容器的底部开始排列
     * 4. space-around 容器内各组件以及与容器之间间距相等
     * 5. space-between 容器内各组之间间距相等(不包含和容器之间)
     */
    

    总结

    好了, 今天就介绍到这里了, 一些常用的简单功能基本上都讲了哈. 可能由于我的水平有限, 讲的不是很清楚, 希望读者谅解. 待我再学些时日, 再来向大家献丑. hhhh(腹黑). 谢谢!

    相关文章

      网友评论

        本文标题:react-native的学习

        本文链接:https://www.haomeiwen.com/subject/dhjqcxtx.html