React Native 学习指南(二) - 天气小项目实战演练

4,803 阅读3分钟

概述

通过上一篇我们已经通过命令行工具构建了第一个 React Native 应用,并在 iOS 设备中成功运行,熟悉了工程的文件代码组织结构。我们将继续使用该工程来开发一个天气应用,以此初步建立对 StyleSheetflexbox用户输入组件添加网络访问 等概念的理解。

创建 WeatherMain.js 并移动默认组件代码

WeatherMain.js

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

export default class WeatherMain extends Component {
  render() {
    return (
      <View style={styles.container}>
        <Text style={styles.welcome}>
          Welcome to Hello RN Weather !
        </Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    backgroundColor: '#F5FCFF',
  },
  welcome: {
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
  },
});

精简 index.ios.jsindex.ios.js

import { AppRegistry } from 'react-native'
import WeatherMain from './WeatherMain'

AppRegistry.registerComponent('HelloRNWeather', () => WeatherMain);

更改 AppDelegate 中根视图组件 moduleName

RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
                                                      moduleName:@"HelloRNWeather"
                                               initialProperties:nil
                                                   launchOptions:launchOptions];

此时,确保项目重新启动可正常运行。

处理用户输入

添加一个输入框,以便用户可通过输入邮编来获取对应地区的天气

render 函数前添加一段处理生命周期的代码

constructor(props) {
    super(props)
    this.state = {
        zip: ''
    }
}

修改显示内容为邮编

<Text style={styles.welcome}>
     地区邮编: {this.state.zip}
</Text>

添加 TextInput 输入框组件,并监听输入事件

<TextInput style={styles.input} onSubmitEditing={(event) => this._handleInputTextDidChanged(event)}/>

styles 中添加新的 input 样式

input: {
  fontSize: 20,
  borderWidth: 3,
  height: 44,
}

添加事件监听回调函数

_handleInputTextDidChanged(event) {
    this.setState({zip: event.nativeEvent.text});
}

记得更新导入语句

import {
  ...
  TextInput,
  ...
} from 'react-native';

在 iOS 模拟器运行项目,现在可以成功显示输入的内容了

处理用户输入

展现数据

mock 一些天气数据

constructor(props) {
    super(props);

    this.state = {
        zip: '',
        forecast: {
            main: 'Snow',
            description: 'very cold',
            temp: 3
        }
    }
}

创建 Forecast.js作为天气预报组件

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

export default class Forecast extends Component {
  render() {
    return (
      <View>
        <Text style={styles.bigText}>
          {this.props.main}
        </Text>
        <Text style={styles.mainText}>
          {this.props.description}
        </Text>
        <Text style={styles.bigText}>
          {this.props.temp} ℃
        </Text>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  bigText: {
    flex: 2,
    fontSize: 20,
    textAlign: 'center',
    margin: 10,
    color: '#374256'
  },
  mainText: {
    flex: 1,
    fontSize: 16,
    textAlign: 'center',
    color: '#374256'
  }
})

Forecast 组件添加到 WeatherMain

import Forecast from './Forecast' // 导入 Forecast 

    <View style={styles.container}>
       ......
       <Forecast main={this.state.forecast.main} description={this.state.forecast.description} temp={this.state.forecast.temp}/>
       ......
    </View>

添加完成后,iOS 模拟器 Command + R 即可看到之前mock的数据展现出来了,至于美观上的问题,接下来专门摸索样式布局的时候再来慢慢解决。

展现数据

添加背景图片

将资源文件放入工程目录

导入 Image 组件

import {
  ...
  Image,
  ...
} from 'react-native';

Image 组件作为容器使用添加到视图中

<Image source={require("./background.jpg")} resizeMode='cover' style={styles.background}>
    <View style={styles.overlay}>
        <Text style={styles.welcome}>
                  地区邮编: {this.state.zip}
        </Text>
        <TextInput style={styles.input} onSubmitEditing={(event) => this._handleInputTextDidChanged(event)}/>
         <Forecast main={this.state.forecast.main} description={this.state.forecast.description} temp={this.state.forecast.temp}/>
     </View>
</Image>

刷新即可看到添加的背景图片了,当然了,仍然还是丑,后面我们再慢慢来解决样式布局问题,感觉前端的布局确实和 AutoLayout 很不一样啊~ /无奈摊手

React Native 添加背景图片

获取网络数据

接下来,我们将尝试通过网络访问来用真实数据来替换之前的 mock 数据。

React Native 中的 fetch 接口基于 Promise 语法风格

fetch('http://wthrcdn.etouch.cn/weather_mini?citykey=101010100')
  .then((response) => response.json())
  .then((responseJSON) => {
     // handle Response
  })
  .catch((error) => {
     console.warn(error);
  })

render 中更新渲染逻辑

render() {
  var content = null;
  if (this.state.forecast !== null) {
     content = <Forecast main={this.state.forecast.main} description={this.state.forecast.description} temp={this.state.forecast.temp}/>;
  }
  ......
}

使用网络访问替代 mock 数据

this.state = {
    zip: '',
    forecast: null
};
fetch('http://wthrcdn.etouch.cn/weather_mini?citykey=101010100')
    .then((res) => {
    return res.json()
    })
    .then((responseJSON) => {
        this.setState({
        forecast: {
          main: responseJSON.data.forecast[0].type,
          description: responseJSON.data.ganmao,
          temp: responseJSON.data.wendu,
        }
     });
    })
    .catch((error) => {
      console.warn(error);
    })

刷新就能看到北京的真实天气了

React-Native 网络访问

== 若出现网络错误,是因为苹果 iOS 9 起不再支持http协议,需要对特定域名进行额外处理。 ==

Info.plist 文件

总结

这样下来,我们就对 StyleSheetflexbox用户输入组件添加网络访问 等概念都有基本的认识,也完成了一个能显示实时天气的小应用了。不过它现在还很简陋、也不美观,接下来我们将在进一步认识移动应用组件后再对样式布局进行优化。

操练代码:Binlogo/HelloReactNative - Github