美文网首页
3,React Native之电影小案例

3,React Native之电影小案例

作者: SYOL | 来源:发表于2017-03-29 15:08 被阅读47次
    var MOCKED_MOVIES_DATA = [
      {title: '标题', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
    ];
    

    2,第二步,需要用到的React Native包和组件

    import React, {
      Component,
    } from 'react';
    import { 
      AppRegistry,
      Image,
      StyleSheet,
      Text,
      View,
    } from 'react-native';
    

    3,第三步在render函数中

      render() {
        var movie = MOCKED_MOVIES_DATA[0];
        return (
          <View style={styles.container}>
              <Image source={{uri: movie.posters.thumbnail}}
                     style={styles.thumbnail}
              />
              <View style={styles.rightContainer}></View>
              <Text>{movie.title}</Text>
              <Text>{movie.year}</Text>
          </View>
        );
      }
    

    4,第四步设置样式

    var styles = StyleSheet.create({
     container: {
        flex: 1,
        justifyContent: 'center',
        alignItems: 'center',
        backgroundColor: '#F5FCFF',
        flexDirection:"row",
      },
      thumbnail: {
        width: 53,
        height: 81,
      },
      rightContainer: {
        flex:1,
      },
      title: {
        fontSize: 20,
        marginBottom: 8,
        textAlign: 'center',
      },
      year: {
        textAlign: 'center',
      },
    });
    

    在模拟器或者真机上就可以查看到这样的效果图

    Paste_Image.png

    5,第五步,拉取真实数据
    A,请求链接

    /***
     * 拉取真实数据(网络JSON数据)
     */
    var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
    

    B,首先在应用中创建一个初始的null状态,这样可以通过this.state.movies == null来判断我们的数据是不是已经被抓取到了。我们在服务器响应返回的时候执行this.setState({movies: moviesData})来改变这个状态。把下面这段代码放到我们的React类的render函数之前

      constructor(props) {
        super(props);   //这一句不能省略,照抄即可
        this.state = {
          movies: null  //这里放你自己定义的state变量及初始值
        };
        // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
        // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
        this.fetchData = this.fetchData.bind(this);
      }
    

    C,组件加载完毕之后,就可以向服务器请求数据。componentDidMount是React组件的一个生命周期方法,它会在组件刚加载完成的时候调用一次,以后不会再被调用。

    componentDidMount() {
        this.fetchData();
      }
    

    D,现在我们来为组件添加fetchData函数。你所需要做的就是在Promise调用链结束后执行this.setState({movies:data})。在React的工作机制下,setState实际上会触发一次重新渲染的流程,此时render函数被触发,发现this.state.movies不再是null。

    fetchData() {
        fetch(REQUEST_URL)
            .then((response) => response.json())
            .then((responseData) => {
              // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
              this.setState({
                movies: responseData.movies,
              });
            });
      }
    

    E,现在我们来修改render函数。在电影数据加载完毕之前,先渲染一个“加载中”的视图;而如果电影数据已经加载完毕了,则渲染第一个电影数据。

    render() {
        if (!this.state.movies) {
          return this.renderLoadingView();
        }
        var movie = this.state.movies[0];
        return this.renderMovie(movie);
      }
      renderLoadingView() {
        return (
            <View style={styles.container}>
              <Text>
                正在加载电影数据……
              </Text>
            </View>
        );
      }
      renderMovie(movie) {
        return (
            <View style={styles.container}>
              <Image
                  source={{uri: movie.posters.thumbnail}}
                  style={styles.thumbnail}
              />
              <View style={styles.rightContainer}>
                <Text style={styles.title}>{movie.title}</Text>
                <Text style={styles.year}>{movie.year}</Text>
              </View>
            </View>
        );
      }
    

    效果如下

    1.gif

    6,问题来了,电影不可能只有一部电影吧。所以需要用到一个新的组件ListView组件。(至于为什么用ListView组件而不用ScrollView组件。原因是把内容放到ListView里,比起直接渲染出所有的元素,或是放到一个ScrollView组件要好,这是因为尽管React很高效,渲染一个可能很大的元素列表还是会很慢。ListView会安排视图的渲染,只显示当前在屏幕上的那些元素。而那些已经渲染好了但移动到了屏幕之外的元素,则会从原生视图结构中移除<以提高性能>。)

    A,添加组件ListView

    import {
      AppRegistry,
      Image,
      ListView,
      StyleSheet,
      Text,
      View,
    } from 'react-native';
    

    B,现在来修改render函数。当我们已经有了数据之后,渲染一个包含多个电影信息的ListView,而不仅仅是单个的电影。

    render() {
        if (!this.state.loaded) {
          return this.renderLoadingView();
        }
        return (
            //dataSource接口用来在ListView的整个更新过程中判断哪些数据行发生了变化。
            <ListView
                dataSource={this.state.dataSource}
                renderRow={this.renderMovie}
                styles={styles.listView}
            />
        );
      }
    

    C,在B中你会注意到我现在用到了this.state中的dataSource。下一步就是在constructor生成的初始状态中添加一个空白的dataSource。另外,我们现在要把数据存储在dataSource中了,所以不再另外用this.state.movies来保存数据。我们可以在state里用一个布尔型的属性(this.state.loaded)来判断数据加载是否已经完成了。

    constructor(props) {
        super(props);   //这一句不能省略,照抄即可
        this.state = {
         dataSource : new ListView.DataSource({
           rowHasChanged:(row1,row2) =>row1 !== row2,
         }),
          loaded:false,
        };
        // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
        // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
        this.fetchData = this.fetchData.bind(this);
      }
    

    D,同时我们也要修改fetchData方法来把数据更新到dataSource里

    fetchData() {
        fetch(REQUEST_URL)
            .then((response) => response.json())
            .then((responseData) => {
              // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
              this.setState({
               dataSource:this.state.dataSource.cloneWithRows(responseData.movies),
                loaded:true,
              });
            });
      }
    

    E,最后添加组件样式

    listView: {
        paddingTop: 20,
        backgroundColor: '#F5FCFF',
      },
    

    最终效果

    2.gif

    最后附上源码

    /**
    * Sample React Native App
    * https://github.com/facebook/react-native
    * @flow
    */
    
    import React, { Component } from 'react';
    import {
     AppRegistry,
     Image,
     ListView,
     StyleSheet,
     Text,
     View,
    } from 'react-native';
    
    /***
    * 拉取真实数据(网络JSON数据)
    */
    var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json';
    
    export default class RNDemo extends Component {
     //首先在应用中创建一个初始的null状态,这样可以通过this.state.movies == null来判断我们的数据是不是已经被抓取到了。我们在服务器响应返回的时候执行this.setState({movies: moviesData})来改变这个状态。把下面这段代码放到我们的React类的render函数之前
     constructor(props) {
       super(props);   //这一句不能省略,照抄即可
       this.state = {
        dataSource : new ListView.DataSource({
          rowHasChanged:(row1,row2) =>row1 !== row2,
        }),
         loaded:false,
       };
       // 在ES6中,如果在自定义的函数里使用了this关键字,则需要对其进行“绑定”操作,否则this的指向不对
       // 像下面这行代码一样,在constructor中使用bind是其中一种做法(还有一些其他做法,如使用箭头函数等)
       this.fetchData = this.fetchData.bind(this);
     }
     //组件加载完毕之后,就可以向服务器请求数据。componentDidMount是React组件的一个生命周期方法,它会在组件刚加载完成的时候调用一次,以后不会再被调用。
     componentDidMount() {
       this.fetchData();
     }
     //现在我们来为组件添加fetchData函数。你所需要做的就是在Promise调用链结束后执行this.setState({movies:data})。在React的工作机制下,setState实际上会触发一次重新渲染的流程,此时render函数被触发,发现this.state.movies不再是null。
     fetchData() {
       fetch(REQUEST_URL)
           .then((response) => response.json())
           .then((responseData) => {
             // 注意,这里使用了this关键字,为了保证this在调用时仍然指向当前组件,我们需要对其进行“绑定”操作
             this.setState({
              dataSource:this.state.dataSource.cloneWithRows(responseData.movies),
               loaded:true,
             });
           });
     }
     //你会注意到我们现在用到了this.state中的dataSource。下一步就是在constructor生成的初始状态中添加一个空白的dataSource。另外,我们现在要把数据存储在dataSource中了,所以不再另外用this.state.movies来保存数据。我们可以在state里用一个布尔型的属性(this.state.loaded)来判断数据加载是否已经完成了。
     render() {
       if (!this.state.loaded) {
         return this.renderLoadingView();
       }
       return (
           //dataSource接口用来在ListView的整个更新过程中判断哪些数据行发生了变化。
           <ListView
               dataSource={this.state.dataSource}
               renderRow={this.renderMovie}
               styles={styles.listView}
           />
       );
     }
       renderLoadingView() {
        return(
            <View style={styles.container}>
              <Text>
                Loading movies...
              </Text>
            </View>
        );
       }
      renderMovie(movie) {
       return (
           <View style={styles.container}>
             <Image
                 source={{uri: movie.posters.thumbnail}}
                 style={styles.thumbnail}
             />
             <View style={styles.rightContainer}>
               <Text style={styles.title}>{movie.title}</Text>
               <Text style={styles.year}>{movie.year}</Text>
             </View>
           </View>
       );
     }
    }
    
    const styles = StyleSheet.create({
     container: {
       flex: 1,
       justifyContent: 'center',
       alignItems: 'center',
       backgroundColor: '#F5FCFF',
       flexDirection:"row",
     },
     thumbnail: {
       width: 53,
       height: 81,
     },
     rightContainer: {
       flex:1,
     },
     title: {
       fontSize: 20,
       marginBottom: 8,
       textAlign: 'center',
     },
     year: {
       textAlign: 'center',
     },
     listView:{
       paddingTop:20,
       backgroundColor:'#F5FCFF',
     },
    });
    
    AppRegistry.registerComponent('RNDemo', () => RNDemo);
    

    本文参考于http://reactnative.cn/docs/0.42/getting-started.html

    相关文章

      网友评论

          本文标题:3,React Native之电影小案例

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