当前位置:Gxlcms > html代码 > ReactNative第一课

ReactNative第一课

时间:2021-07-01 10:21:17 帮助过:31人阅读

  

  前言

  本篇文章的作用在于帮助你快速上手使用React Native编写iOS应用。如果你现在还不太了解React Native是什么以及Facebook为什么要创建React Native,你可以先看看这篇博客。

  阅读本文之前,我们假设你已经有过使用React创建网站的经验。如果你还是一个React新手,那么我们建议你从React的网站开始学习。


  设置

  使用React Native开发iOS应用需要OSX系统,Xcode,Homebrew,node,npm以及watchman,你也可以有选择的使用Flow。

  在安装完这些依赖项目之后,你可以简单的使用两行命令来开启一个React Native项目:

  npm install -g react-native-cli

  react-native-cli是用来开发React Native的命令行工具。你需要使用npm来安装它。上面这行代码将会帮助你在terminal中安装react-native命令。当然,你只需要运行一次这行代码。

  react-native init AwsomeProject

  这行代码可以获取所有React Native的源码以及依赖项,同时会创建一个叫做AwsomeProject/AwsomeProject.xcodeproj的全新Xcode项目。


  开发

  现在你可以在Xcode中开发这个新项目(AwsomeProject/AwsomeProject.xcodeproj),并简单的使用cmd+R来运行它。运行代码的同时也会自动开启一个node服务器来实现代码的热重载。这样一来你就可以通过cmd+R来查看变化而不需要每次都在Xcode中进行重编译。

  在本文中我们将创建一个简单的电影应用,这个应用将抓取目前正在上映的最新的25部电影,并将它们展示在一个ListView中。


  Hello World

  react-native init会复制Example/SampleProject中的内容到你命名的项目中,在本文中项目名称为AwsomeProject。这是一个简单的hello world应用。你可以通过编辑index.os.js来改变这个应用,然后使用cmd+R在模拟器中查看变化。


  伪造数据

  在我们开始编写代码从Rotten Tomatoes网站抓取数据之前,我们先来伪造一些数据以便我们可以马上体验一下React Native。在Facebook我们一般会在JS文件的顶部声明常量,并在后面使用,但是随便你加在哪里都好。在index.ios.js中添加以下代码:

  1. var MOCKED_**_DATA = [
  2. {title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}},
  3. ];


  渲染一部电影

  我们会渲染电影标题,年份以及电影海报略缩图。由于略缩图在React Native中是一个Image组件,我们需要将Imagei到React的依赖项中。

  1. var {
  2. AppRegistry,
  3. Image,
  4. StyleSheet,
  5. Text,
  6. View,
  7. } = React;

  现在我们修改render函数以便我们可以将上面渲染上面的数据而不仅仅是渲染一个hello world:

  1. render: function() {
  2. var movie = MOCKED_**_DATA[0];
  3. return (
  4. <view style="{styles.container}">
  5. <text>{movie.title}</text>
  6. <text>{movie.year}</text>
  7. <img source="{{uri:" movie.posters.thumbnail}}="">
  8. </view>
  9. );
  10. }

  按下cmd+R你应该在”2015”上面看到”Title”。注意此时Image什么都不会渲染。这是因为我们还没有指定想要的宽度和高度。这需要通过styles属性来设置。在我们修改styles的同时我们还需要把那些不再会使用的样式删除:

  1. var styles = StyleSheet.create({
  2. container: {
  3. flex: 1,
  4. justifyContent: 'center',
  5. alignItems: 'center',
  6. backgroundColor: '#F5FCFF',
  7. },
  8. thumbnail: {
  9. width: 53,
  10. height: 81,
  11. },
  12. });

  最后我们需要将样式运用在Image组件上。

  1. <img source="{{uri:" movie.posters.thumbnail}}="" style="{styles.thumbnail}">

  按下cmd+R你会发现图片已经渲染出来了。

  

#图片1

  添加其他样式

  很好,我们现在已经把数据渲染出来了。现在我们来让我们的应用变得好看一些。我想把文字放在图片的右侧,同时让标题大一些并居中:

  1. +---------------------------------+
  2. |+-------++----------------------+|
  3. || || Title ||
  4. || Image || ||
  5. || || Year ||
  6. |+-------++----------------------+|
  7. +---------------------------------+

  我们会添加另一个container,这是为了让我们的组件在外层的组件中垂直居中。

  1. return (
  2. <view style="{styles.container}">
  3. <img source="{{uri:" movie.posters.thumbnail}}="" style="{styles.thumbnail}">
  4. <view style="{styles.rightContainer}">
  5. <text style="{styles.title}">{movie.title}</text>
  6. <text style="{styles.year}">{movie.year}</text>
  7. </view>
  8. </view>
  9. );

  现在并没有多少变化,我们在文字外层添加了一个包裹容器并将其放在了图片后面(因为文字要在图片的右边)。现在我们来看看样式会变成什么样:

  1. container: {
  2. flex: 1,
  3. flexDirection: 'row',
  4. justifyContent: 'center',
  5. alignItems: 'center',
  6. backgroundColor: '#F5FCFF',
  7. },

  我们在这里使用弹性盒模型来布局,如果你不熟悉弹性盒模型,可以看看这个教程。

  在上面的代码中,我们简单的添加了flexDirection: 'row'来确保我们的main container是水平布局而不是垂直布局。


  现在我们添加另一组样式:

  1. rightContainer: {
  2. flex: 1,
  3. },

  上面代码的意思是rightContainer会占据外层容器右边的空间,左边则是图片。如果没有看出效果,可以为rightContainer添加一个backgroundColor属性,同时移除flex: 1。你会看到外出容器的体积会变得劲量的小来适应子容器。

  而文本的样式很直观:

  1. title: {
  2. fontSize: 20,
  3. marginBottom: 8,
  4. textAlign: 'center',
  5. },
  6. year: {
  7. textAlign: 'center',
  8. },

  继续按下cmd+R来查看更新之后的视图:

enter image description here

  抓取真实数据

  从Rotten Tomatoes的API抓取数据和学习React Native并没有多少关系,所以你可以风轻云淡的跳过这一节。

  将下面的常量放在文件的顶部来创建一个请求数据使用的REQUEST_URL:

  1. var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
  2. var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/**in_theaters.json';
  3. var PAGE_SIZE = 25;
  4. var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
  5. var REQUEST_URL = API_URL + PARAMS;

  为我们的应用添加初始状态以便我们可以通过检查this.state.** === null来确定电影数据有没有被城管加载。当电影数据返回时,我们可以通过this.setState({**: **Data})来设置数据。将下面的代码添加到render函数之前:

  1. getInitialState: function() {
  2. return {
  3. **: null,
  4. };
  5. },

  我们想要在组件完成加载后发送请求,componentDidMount是React组件中的一个函数,它只会在组件加载完成之后被调用一次。

  1. componentDidMount: function() {
  2. this.fetchData();
  3. },

  现在添加组件中会用到的fetchData函数。这个方法将负责处理数据抓取。你需要做的仅仅是在promise完成解析之后调用this.setState({**: data}),因为setState会触发重新渲染,而此时render函数会注意到this.state.**不再是null。注意我们会在promise链的最后调用done()–一定要确保调用done(),否则错误信息可能会被忽略。

  1. fetchData: function() {
  2. fetch(REQUEST_URL)
  3. .then((response) => response.json())
  4. .then((responseData) => {
  5. this.setState({
  6. **: responseData.**,
  7. });
  8. })
  9. .done();
  10. },

  现在修改render函数来渲染一个loading视图,如果电影数据还没有返回的话,否则将渲染第一部电影:

  1. render: function() {
  2. if (!this.state.**) {
  3. return this.renderLoadingView();
  4. }
  5. var movie = this.state.**[0];
  6. return this.renderMovie(movie);
  7. },
  8. renderLoadingView: function() {
  9. return (
  10. <view style="{styles.container}">
  11. <text>
  12. Loading **...
  13. </text>
  14. </view>
  15. );
  16. },
  17. renderMovie: function(movie) {
  18. return (
  19. <view style="{styles.container}">
  20. <img source="{{uri:" movie.posters.thumbnail}}="" style="{styles.thumbnail}">
  21. <view style="{styles.rightContainer}">
  22. <text style="{styles.title}">{movie.title}</text>
  23. <text style="{styles.year}">{movie.year}</text>
  24. </view>
  25. </view>
  26. );
  27. },

  现在按下cmd+R,你应该已经看到了”Loading **…”,直到电影数据返回,接着页面就会渲染第一部从Rotten Tomatoes抓回来的电影:

  

enter image description here

  ListView

  现在我们来修改应用来将所有的数据渲染在一个ListView组件种,而不是只渲染一部电影。

  为什么使用ListView要比把所有数据放在一个ScrollView里面好呢?虽然React速度很快,但是渲染一个可能是无限长的列表依然可能很慢。ListView会自动渲染视线之内的视图,而那些在屏幕之外的视图会被暂时移除。

  第一件事:在文件的最上方添加ListView:

  1. var {
  2. AppRegistry,
  3. Image,
  4. ListView,
  5. StyleSheet,
  6. Text,
  7. View,
  8. } = React;

  现在修改render函数以便一旦我们的数据返回沃恩就可以在一个ListView里面渲染数据:

  1. render: function() {
  2. if (!this.state.loaded) {
  3. return this.renderLoadingView();
  4. }
  5. return (
  6. <listview datasource="{this.state.dataSource}" renderrow="{this.renderMovie}" style="{styles.listView}">
  7. );
  8. }</listview>

  DataSource是一个ListView的接口,作用是决定那些行会被改变。

  注意在这里使用dataSource而不是this.state。下一步我们需要在getInitialState的返回对象上添加一个空的dataSource,我们不能再使用this.state.**防止数据被存储两次。我们可以使用state的布尔值属性(this.state.loaded)来判断数据抓取是否结束:

  1. getInitialState: function() {
  2. return {
  3. dataSource: new ListView.DataSource({
  4. rowHasChanged: (row1, row2) => row1 !== row2,
  5. }),
  6. loaded: false,
  7. };
  8. },

  在这里我们还需要修改fetchData方法来更新state:

  1. fetchData: function() {
  2. fetch(REQUEST_URL)
  3. .then((response) => response.json())
  4. .then((responseData) => {
  5. this.setState({
  6. dataSource: this.state.dataSource.cloneWithRows(responseData.**),
  7. loaded: true,
  8. });
  9. })
  10. .done();
  11. },

  最后,我们在styles中为ListView组件添加样式:

  1. listView: {
  2. paddingTop: 20,
  3. backgroundColor: '#F5FCFF',
  4. },

  下面是最终的效果图:

  

#图4

  接下来我们还可以通过添加导航,搜索,无线滚动加载等等来弯沉一个完整的应用。你可以查看[电影示例](** Example)来查看完整的代码。


  完整的源码

  1. /**
  2. * Sample React Native App
  3. * https://github.com/facebook/react-native
  4. */
  5. 'use strict';
  6. var React = require('react-native');
  7. var {
  8. AppRegistry,
  9. Image,
  10. ListView,
  11. StyleSheet,
  12. Text,
  13. View,
  14. } = React;
  15. var API_KEY = '7waqfqbprs7pajbz28mqf6vz';
  16. var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/**in_theaters.json';
  17. var PAGE_SIZE = 25;
  18. var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE;
  19. var REQUEST_URL = API_URL + PARAMS;
  20. var AwesomeProject = React.createClass({
  21. getInitialState: function() {
  22. return {
  23. dataSource: new ListView.DataSource({
  24. rowHasChanged: (row1, row2) => row1 !== row2,
  25. }),
  26. loaded: false,
  27. };
  28. },
  29. componentDidMount: function() {
  30. this.fetchData();
  31. },
  32. fetchData: function() {
  33. fetch(REQUEST_URL)
  34. .then((response) => response.json())
  35. .then((responseData) => {
  36. this.setState({
  37. dataSource: this.state.dataSource.cloneWithRows(responseData.**),
  38. loaded: true,
  39. });
  40. })
  41. .done();
  42. },
  43. render: function() {
  44. if (!this.state.loaded) {
  45. return this.renderLoadingView();
  46. }
  47. return (
  48. <listview datasource="{this.state.dataSource}" renderrow="{this.renderMovie}" style="{styles.listView}">
  49. );
  50. },
  51. renderLoadingView: function() {
  52. return (
  53. <view style="{styles.container}">
  54. <text>
  55. Loading **...
  56. </text>
  57. </view>
  58. );
  59. },
  60. renderMovie: function(movie) {
  61. return (
  62. <view style="{styles.container}">
  63. <img source="{{uri:" movie.posters.thumbnail}}="" style="{styles.thumbnail}">
  64. <view style="{styles.rightContainer}">
  65. <text style="{styles.title}">{movie.title}</text>
  66. <text style="{styles.year}">{movie.year}</text>
  67. </view>
  68. </view>
  69. );
  70. },
  71. });
  72. var styles = StyleSheet.create({
  73. container: {
  74. flex: 1,
  75. flexDirection: 'row',
  76. justifyContent: 'center',
  77. alignItems: 'center',
  78. backgroundColor: '#F5FCFF',
  79. },
  80. rightContainer: {
  81. flex: 1,
  82. },
  83. title: {
  84. fontSize: 20,
  85. marginBottom: 8,
  86. textAlign: 'center',
  87. },
  88. year: {
  89. textAlign: 'center',
  90. },
  91. thumbnail: {
  92. width: 53,
  93. height: 81,
  94. },
  95. listView: {
  96. paddingTop: 20,
  97. backgroundColor: '#F5FCFF',
  98. },
  99. });
  100. AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);</listview>


来源http://facebook.github.io/react-native/docs/tutorial.htm


人气教程排行