菜鸟初探React Native 回合二

前言

第一回合 我们初步了解到了RN的环境和语法,然后我们继续往下看

继第一个项目demo往下延伸新的代码,今天要做一个城市列表

城市列表

拆分目录

这里,我们做一个城市列表,真实的访问接口获取数据,然后渲染页面,看看做出来效果如何。

首先,我们初始化一个RN项目:

react-native init Citylist

然后使用Xcode打开iOS中的项目,编译运行:

import React, { Component } from 'react';

import {

    AppRegistry,

    StyleSheet,

    Text,

    View } from 'react-native';

export default class Citylist extends Component {

    render() {

            return(

                <View style={styles.container}>

                    <Text style={styles.welcome}>

                    Welcome to React Native!

                    </Text>

                    <Text style={styles.instructions} >

                     To get started, edit index.ios.js

                    </Text>

                     <Text style={styles.instructions} >

                     Press Cmd+R to reload,{'\n'} Cmd+D or shake for dev menu

                      </Text>

                 </View>   

        );

    }

}

const styles = StyleSheet.create({

    container: {

        flex: 1,

        justifyContent: 'center',

        alignItems: 'center',

        backgroundColor: '#F5FCFF',

    },

    welcome: {

        fontSize: 20,

        textAlign: 'center',

        margin: 10,

    },

        instructions: {

        textAlign: 'center',

        color: '#333333',

        marginBottom: 5,

    },

});

AppRegistry.registerComponent('Citylist', () => Citylist);


这里除了index.io.js,其他文件我们不必理睬,我们做的第一件事情是,将样式文件剥离出去,新建static文件夹,加入images和style,将样式文件移入style文件,新建style.js:

import {

    StyleSheet

} from 'react-native';

export let styles = StyleSheet.create({

    container: {

        flex: 1,

        justifyContent: 'center',

        alignItems: 'center',

        backgroundColor: '#F5FCFF',

    },

    welcome: {

        fontSize: 20,

        textAlign: 'center',

        margin: 10,

    },

instructions: {

        textAlign: 'center',

        color: '#333333',

        marginBottom: 5,

    },

});

然后首页代码再做一些改动,在import后边插入本行代码:

import {styles} from './static/style/style';

PS:这里有一个箭头函数

() => Citylist

//===>

function () {

return Citylist;

}

静态资源剥离后,我们先不处理其它的,我们来做数据请求。

数据请求

RN虽然内置了ajax库,但是一般推荐使用RN自带的Fetch,最简单的使用是:

fetch('https://mywebsite.com/mydata.json')

PS:我们在学习RN的时候,也是在学习神马方式是适合的,或者说熟悉使用合适的组件

请求一个接口是这样写的(使用promise):

fetch('https://apikuai.baidu.com/city/getstartcitys')

    .then((response) => response.json())

    .then((jsonData) => { console.log(jsonData);

})

.catch((e) => {

    console.log(e)

})

这里打开调试环境一看,输出了我们要的数据:


一般来说,我们需要对数据请求应该封装为一个底层库,这里只做一些简单改造,真实项目不会这样做:

export default class Citylist extends Component {

    getdata(url, suc, err) {

    return fetch(url)

    .then((response) => response.json())

    .then((data) => {

    if(data.errno == 0) {

        suc && suc(data.data)

        }

    })

    .catch((e) => {

        console.log(e)

        });

      }

    render() {

        this.getdata('https://apikuai.baidu.com/city/getstartcitys', function(data) {

            s = ''

    });

PS:这里的使用不一定正确,先完成功能再改进吧

我们取所有的城市cities,这个数据量很大,有1000多条记录,也可以测试下拖动效率了,这里为类加入构造函数,因为列表是可变的,暂时把列表数据归为state(react也不是太熟,如果有问题后续优化,先完成功能):

constructor(props) {

    super(props);

    this.state = {

    cities: []

    };

}

 var scope = this;

this.getdata('https://apikuai.baidu.com/city/getstartcitys', function(data) {

scope.state.citys = data.cities;

});

列表渲染

处理了数据问题后,我们开始做列表渲染,这里使用ListView组件,这个组件用以显示一个垂直滚动列表,适合长列表,两个必须的属性是datasource和renderRow:

dataSource:列表数据源

renderRow:逐个解析数据源中的数据,然后返回一个设定好的格式来渲染

简单书写代码:

export default class Citylist extends Component {

    constructor(props) {

        super(props);

    this.ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});

    this.state = {

        cities: this.ds.cloneWithRows([

                {cnname : "文山壮族苗族自治州",

                enname : "wszzmzzzz",

                extflag : "1",

                flag : "0",

                name : "wenshanzhuangzumiaozuzizhizhou",

                parentid : "28",

                regionid : "177",

                shortname : "文山",

                shownname : "文山",

                type : "2"

        },{

                cnname : "文山壮族苗族自治州",

                enname : "wszzmzzzz",

                extflag : "1",

                flag : "0",

                name : "wenshanzhuangzumiaozuzizhizhou",

                parentid : "28",

                regionid : "177",

                shortname : "文山",

                shownname : "文山",

                type : "2"

        },{

                cnname : "文山壮族苗族自治州",

                enname : "wszzmzzzz",

                extflag : "1",

                flag : "0",

                name : "wenshanzhuangzumiaozuzizhizhou",

                parentid : "28",

                regionid : "177",

                shortname : "文山",

                shownname : "文山",

                type : "2"} ]

        )

    };

}

getdata(url, suc, err) {

        return fetch(url)

        .then((response) => response.json())

        .then((data) => {

            if(data.errno == 0) {

                suc && suc(data.data)

            }

        })

        .catch((e) => { console.log(e) }); }

componentDidMount(){

        var scope = this;

        this.getdata('https://apikuai.baidu.com/city/getstartcitys', function(data) {

                console.log(data)

                scope.setState({ cities: scope.ds.cloneWithRows(data.cities) });

                //scope.state.citys = data.cities;

                //this.getdata('https://apikuai.baidu.com/city/getstartcitys', (data) => {

                // this.state.citys = data.cities;

                //});

        });

}

render() {

        return (

                <View style={styles.container}>

                    <LisrView

                                dataSource={this.state.cities}

                                renderRow={(rowData) =><Text>{rowData.cnname}</Text>

                    />

            </View>

        ); }}


然后就这样了,虽然丑是丑点,但是还能看嘛,这里我们先不去理睬城市的排序,也不做搜索功能,我们先把布局处理下,他的丑陋我已经受不了了

样式处理

现在我们开始处理这段样式:

import {

        StyleSheet

} from 'react-native';

export let styles = StyleSheet.create({

        container: {

                flex: 1,

                backgroundColor: '#F5FCFF',

            },

          listView: {

                marginTop: 30,

                flex: 1,

                borderBottomColor:'#CCCCCC',

                //cell的分割线

                borderBottomWidth:1

            },

                listItem: {

                        paddingTop: 15,

                        paddingBottom: 15,

                        paddingLeft: 10,

                        flexDirection:'row',

                        borderBottomColor:'#CCCCCC',

                        //cell的分割线

                        borderBottomWidth:1

} });


事件绑定

然后,我们再为每行数据加上点击事件,这里也做简单一点,打印出当前行的值即可:

onPressAction(data){

        alert(data.cnname)

    }

    render() {

            return (

            <View  style={styles.container}>

            <ListView style={styles.listView} enableEmptySections={true}

            dataSource={this.state.cities}

            renderRow={(rowData) =>

            <View  style={styles.listItem}>

                    <Text onPress={() => this.onPressAction(rowData)}>{rowData.cnname} </Text>    

            </View>

            }

    />

</View>

); }


PS:我尼玛,这个RN的学习,很大程度就是一个个API或者组件的熟悉,这块不熟悉的话,做起来恼火的很

我这里开始想给Text设置边框,怎么都不能成功,后面就加了一层View就好了,这种小细节需要多摸索,这个是最终的结构:


结语

作为一个demo的话,这个例子基本可以说明一些问题的,虽然我本意是想做成这个样子的:)


通过这个例子,我们简单的学习了下RN的开发模式,做出来的感受是Facebook很强大,做了一个体系性的东西,举个例子来说(个人感受

之前我们做Hybrid的时候Header是Native提供的,大概做法是这样的:

//Native以及前端框架会对特殊tagname的标识做默认回调,如果未注册callback,或者点击回调callback无返回则执行默认方法

//back前端默认执行History.back,如果不可后退则回到指定URL,Native如果检测到不可后退则返回Naive大首页

//home前端默认返回指定URL,Native默认返回大首页

this.header.set({

        left: [ {

            //如果出现value字段,则默认不使用icon

            tagname: 'back', value: '回退',

            //如果设置了lefticon或者righticon,则显示icon

            //native会提供常用图标icon映射,如果找不到,便会去当前业务频道专用目录获取图标

            lefticon: 'back',

            callback: function () { }

        }

    ],

        right: [ {

        //默认icon为tagname,这里为icon

        tagname: 'search',

        callback: function () { }

    },

    //自定义图标

    { tagname: 'me',

        //会去hotel频道存储静态header图标资源目录搜寻该图标,没有便使用默认图标

        icon: 'hotel/me.png',

        callback: function () { }

        }

    ],

        title: 'title',

        //显示主标题,子标题的场景

        title: ['title', 'subtitle'],

        //定制化title

        title: {

        value: 'title',

        //标题右边图标

        righticon: 'down',

        //也可以设置lefticon

        //标题类型,默认为空,设置的话需要特殊处理

        //type: 'tabs',

        //点击标题时的回调,默认为空

        callback: function () { } } });

通过这个约定,我们的Native就会生成一系列headerUI:


而RN做了什么呢,他可能是实现了一个这样的标签(或者说是语法):

< Header title="" right="[]" ></ Header>

然后RN会自己去解析这个标签,生成上述的对象,然后生成Native的UI,这个我们其实也能做到,但是我们一个能做到,10个就不一定做得到了,RN牛的地方就牛在他提供了这么大一坨东西:


然后还有他一整套的样式体系,非常之大手笔,而通过RN的完善约定,生成了一套NativeUI,应该说来体验是非常高的,开发效率因为可以做到大部分iOS Android通用,虽然整体开发效率无法与Hybrid比肩,但绝对有其应用场景。

我们也有一些同事说了一些RN的问题,但是框架在发展,容器在优化,这些问题在某个时间点应该能解决的,总的说来,RN还是很有学习的价值,后面我可能会花很多功夫去进行落地!!!

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

推荐阅读更多精彩内容